Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Bundle formidable dependancy

  • Loading branch information...
commit b23a92d0484bf1ae26f6dfe9b86a22dcc5a9bc6e 1 parent 02a6fd0
@daleharvey authored
Showing with 3,517 additions and 11 deletions.
  1. +1 −11 README.markdown
  2. +4 −0 node_modules/formidable/.npmignore
  3. +4 −0 node_modules/formidable/.travis.yml
  4. +14 −0 node_modules/formidable/Makefile
  5. +311 −0 node_modules/formidable/Readme.md
  6. +3 −0  node_modules/formidable/TODO
  7. +70 −0 node_modules/formidable/benchmark/bench-multipart-parser.js
  8. +43 −0 node_modules/formidable/example/post.js
  9. +48 −0 node_modules/formidable/example/upload.js
  10. +1 −0  node_modules/formidable/index.js
  11. +73 −0 node_modules/formidable/lib/file.js
  12. +384 −0 node_modules/formidable/lib/incoming_form.js
  13. +3 −0  node_modules/formidable/lib/index.js
  14. +312 −0 node_modules/formidable/lib/multipart_parser.js
  15. +25 −0 node_modules/formidable/lib/querystring_parser.js
  16. +6 −0 node_modules/formidable/lib/util.js
  17. +4 −0 node_modules/formidable/node-gently/Makefile
  18. +167 −0 node_modules/formidable/node-gently/Readme.md
  19. +22 −0 node_modules/formidable/node-gently/example/dog.js
  20. +11 −0 node_modules/formidable/node-gently/example/event_emitter.js
  21. +1 −0  node_modules/formidable/node-gently/index.js
  22. +184 −0 node_modules/formidable/node-gently/lib/gently/gently.js
  23. +1 −0  node_modules/formidable/node-gently/lib/gently/index.js
  24. +14 −0 node_modules/formidable/node-gently/package.json
  25. +8 −0 node_modules/formidable/node-gently/test/common.js
  26. +348 −0 node_modules/formidable/node-gently/test/simple/test-gently.js
  27. +29 −0 node_modules/formidable/package.json
  28. +19 −0 node_modules/formidable/test/common.js
  29. +1 −0  node_modules/formidable/test/fixture/file/funkyfilename.txt
  30. +1 −0  node_modules/formidable/test/fixture/file/plain.txt
  31. +3 −0  node_modules/formidable/test/fixture/http/special-chars-in-filename/info.md
  32. +3 −0  node_modules/formidable/test/fixture/js/no-filename.js
  33. +21 −0 node_modules/formidable/test/fixture/js/special-chars-in-filename.js
  34. +72 −0 node_modules/formidable/test/fixture/multipart.js
  35. +89 −0 node_modules/formidable/test/integration/test-fixtures.js
  36. +24 −0 node_modules/formidable/test/legacy/common.js
  37. +80 −0 node_modules/formidable/test/legacy/integration/test-multipart-parser.js
  38. +104 −0 node_modules/formidable/test/legacy/simple/test-file.js
  39. +727 −0 node_modules/formidable/test/legacy/simple/test-incoming-form.js
  40. +50 −0 node_modules/formidable/test/legacy/simple/test-multipart-parser.js
  41. +45 −0 node_modules/formidable/test/legacy/simple/test-querystring-parser.js
  42. +75 −0 node_modules/formidable/test/legacy/system/test-multi-video-upload.js
  43. +2 −0  node_modules/formidable/test/run.js
  44. +63 −0 node_modules/formidable/test/unit/test-incoming-form.js
  45. +47 −0 node_modules/formidable/tool/record.js
View
12 README.markdown
@@ -12,20 +12,11 @@ Dependencies
* nodejs - http://nodejs.org
* npmjs - http://npmjs.org
- * formidable
-
-Install *formidable* via npm:
-
- $ npm install formidable
Building
========
-Install via [npm](http://npmjs.org/)
-
- $ npm install jshint-mode
-
-or you can [download](https://github.com/daleharvey/jshint-mode/tarball/master) or clone
+[download](https://github.com/daleharvey/jshint-mode/tarball/master) or clone
$ git clone git://github.com/daleharvey/jshint-mode.git
@@ -69,4 +60,3 @@ Note to Emacs.app users
If use Emacs.app on OS X, you need to set the following environment variables:
* PATH - Add path to your *node* executable
- * NODE_PATH - Add path to where your node_modules are located so node can find the *formidable* module
View
4 node_modules/formidable/.npmignore
@@ -0,0 +1,4 @@
+/test/tmp/
+*.upload
+*.un~
+*.http
View
4 node_modules/formidable/.travis.yml
@@ -0,0 +1,4 @@
+language: node_js
+node_js:
+ - 0.4
+ - 0.6
View
14 node_modules/formidable/Makefile
@@ -0,0 +1,14 @@
+SHELL := /bin/bash
+
+test:
+ @./test/run.js
+
+build: npm test
+
+npm:
+ npm install .
+
+clean:
+ rm test/tmp/*
+
+.PHONY: test clean build
View
311 node_modules/formidable/Readme.md
@@ -0,0 +1,311 @@
+# Formidable
+
+[![Build Status](https://secure.travis-ci.org/felixge/node-formidable.png?branch=master)](http://travis-ci.org/felixge/node-formidable)
+
+## Purpose
+
+A node.js module for parsing form data, especially file uploads.
+
+## Current status
+
+This module was developed for [Transloadit](http://transloadit.com/), a service focused on uploading
+and encoding images and videos. It has been battle-tested against hundreds of GB of file uploads from
+a large variety of clients and is considered production-ready.
+
+## Features
+
+* Fast (~500mb/sec), non-buffering multipart parser
+* Automatically writing file uploads to disk
+* Low memory footprint
+* Graceful error handling
+* Very high test coverage
+
+## Changelog
+
+### v1.0.9
+
+* Emit progress when content length header parsed (Tim Koschützki)
+* Fix Readme syntax due to GitHub changes (goob)
+* Replace references to old 'sys' module in Readme with 'util' (Peter Sugihara)
+
+### v1.0.8
+
+* Strip potentially unsafe characters when using `keepExtensions: true`.
+* Switch to utest / urun for testing
+* Add travis build
+
+### v1.0.7
+
+* Remove file from package that was causing problems when installing on windows. (#102)
+* Fix typos in Readme (Jason Davies).
+
+### v1.0.6
+
+* Do not default to the default to the field name for file uploads where
+ filename="".
+
+### v1.0.5
+
+* Support filename="" in multipart parts
+* Explain unexpected end() errors in parser better
+
+**Note:** Starting with this version, formidable emits 'file' events for empty
+file input fields. Previously those were incorrectly emitted as regular file
+input fields with value = "".
+
+### v1.0.4
+
+* Detect a good default tmp directory regardless of platform. (#88)
+
+### v1.0.3
+
+* Fix problems with utf8 characters (#84) / semicolons in filenames (#58)
+* Small performance improvements
+* New test suite and fixture system
+
+### v1.0.2
+
+* Exclude node\_modules folder from git
+* Implement new `'aborted'` event
+* Fix files in example folder to work with recent node versions
+* Make gently a devDependency
+
+[See Commits](https://github.com/felixge/node-formidable/compare/v1.0.1...v1.0.2)
+
+### v1.0.1
+
+* Fix package.json to refer to proper main directory. (#68, Dean Landolt)
+
+[See Commits](https://github.com/felixge/node-formidable/compare/v1.0.0...v1.0.1)
+
+### v1.0.0
+
+* Add support for multipart boundaries that are quoted strings. (Jeff Craig)
+
+This marks the beginning of development on version 2.0 which will include
+several architectural improvements.
+
+[See Commits](https://github.com/felixge/node-formidable/compare/v0.9.11...v1.0.0)
+
+### v0.9.11
+
+* Emit `'progress'` event when receiving data, regardless of parsing it. (Tim Koschützki)
+* Use [W3C FileAPI Draft](http://dev.w3.org/2006/webapi/FileAPI/) properties for File class
+
+**Important:** The old property names of the File class will be removed in a
+future release.
+
+[See Commits](https://github.com/felixge/node-formidable/compare/v0.9.10...v0.9.11)
+
+### Older releases
+
+These releases were done before starting to maintain the above Changelog:
+
+* [v0.9.10](https://github.com/felixge/node-formidable/compare/v0.9.9...v0.9.10)
+* [v0.9.9](https://github.com/felixge/node-formidable/compare/v0.9.8...v0.9.9)
+* [v0.9.8](https://github.com/felixge/node-formidable/compare/v0.9.7...v0.9.8)
+* [v0.9.7](https://github.com/felixge/node-formidable/compare/v0.9.6...v0.9.7)
+* [v0.9.6](https://github.com/felixge/node-formidable/compare/v0.9.5...v0.9.6)
+* [v0.9.5](https://github.com/felixge/node-formidable/compare/v0.9.4...v0.9.5)
+* [v0.9.4](https://github.com/felixge/node-formidable/compare/v0.9.3...v0.9.4)
+* [v0.9.3](https://github.com/felixge/node-formidable/compare/v0.9.2...v0.9.3)
+* [v0.9.2](https://github.com/felixge/node-formidable/compare/v0.9.1...v0.9.2)
+* [v0.9.1](https://github.com/felixge/node-formidable/compare/v0.9.0...v0.9.1)
+* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
+* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
+* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
+* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
+* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
+* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
+* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
+* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
+* [v0.1.0](https://github.com/felixge/node-formidable/commits/v0.1.0)
+
+## Installation
+
+Via [npm](http://github.com/isaacs/npm):
+
+ npm install formidable@latest
+
+Manually:
+
+ git clone git://github.com/felixge/node-formidable.git formidable
+ vim my.js
+ # var formidable = require('./formidable');
+
+Note: Formidable requires [gently](http://github.com/felixge/node-gently) to run the unit tests, but you won't need it for just using the library.
+
+## Example
+
+Parse an incoming file upload.
+
+ var formidable = require('formidable'),
+ http = require('http'),
+
+ util = require('util');
+
+ http.createServer(function(req, res) {
+ if (req.url == '/upload' && req.method.toLowerCase() == 'post') {
+ // parse a file upload
+ var form = new formidable.IncomingForm();
+ form.parse(req, function(err, fields, files) {
+ res.writeHead(200, {'content-type': 'text/plain'});
+ res.write('received upload:\n\n');
+ res.end(util.inspect({fields: fields, files: files}));
+ });
+ return;
+ }
+
+ // show a file upload form
+ res.writeHead(200, {'content-type': 'text/html'});
+ res.end(
+ '<form action="/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>'
+ );
+ }).listen(80);
+
+## API
+
+### formidable.IncomingForm
+
+__new formidable.IncomingForm()__
+
+Creates a new incoming form.
+
+__incomingForm.encoding = 'utf-8'__
+
+The encoding to use for incoming form fields.
+
+__incomingForm.uploadDir = process.env.TMP || '/tmp' || process.cwd()__
+
+The directory for placing file uploads in. You can move them later on using
+`fs.rename()`. The default directory is picked at module load time depending on
+the first existing directory from those listed above.
+
+__incomingForm.keepExtensions = false__
+
+If you want the files written to `incomingForm.uploadDir` to include the extensions of the original files, set this property to `true`.
+
+__incomingForm.type__
+
+Either 'multipart' or 'urlencoded' depending on the incoming request.
+
+__incomingForm.maxFieldsSize = 2 * 1024 * 1024__
+
+Limits the amount of memory a field (not file) can allocate in bytes.
+If this value is exceeded, an `'error'` event is emitted. The default
+size is 2MB.
+
+__incomingForm.hash = false__
+
+If you want checksums calculated for incoming files, set this to either `'sha1'` or `'md5'`.
+
+__incomingForm.bytesReceived__
+
+The amount of bytes received for this form so far.
+
+__incomingForm.bytesExpected__
+
+The expected number of bytes in this form.
+
+__incomingForm.parse(request, [cb])__
+
+Parses an incoming node.js `request` containing form data. If `cb` is provided, all fields an files are collected and passed to the callback:
+
+ incomingForm.parse(req, function(err, fields, files) {
+ // ...
+ });
+
+__incomingForm.onPart(part)__
+
+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.
+
+ incomingForm.onPart = function(part) {
+ part.addListener('data', function() {
+ // ...
+ });
+ }
+
+If you want to use formidable to only handle certain parts for you, you can do so:
+
+ incomingForm.onPart = function(part) {
+ if (!part.filename) {
+ // let formidable handle all non-file parts
+ incomingForm.handlePart(part);
+ }
+ }
+
+Check the code in this method for further inspiration.
+
+__Event: 'progress' (bytesReceived, bytesExpected)__
+
+Emitted after each incoming chunk of data that has been parsed. Can be used to roll your own progress bar.
+
+__Event: 'field' (name, value)__
+
+Emitted whenever a field / value pair has been received.
+
+__Event: 'fileBegin' (name, file)__
+
+Emitted whenever a new file is detected in the upload stream. Use this even if
+you want to stream the file to somewhere else while buffering the upload on
+the file system.
+
+__Event: 'file' (name, file)__
+
+Emitted whenever a field / file pair has been received. `file` is an instance of `File`.
+
+__Event: 'error' (err)__
+
+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.
+
+__Event: '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. In the future there will be a separate 'timeout' event (needs a change in the node core).
+
+__Event: '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.
+
+### formidable.File
+
+__file.size = 0__
+
+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.path = null__
+
+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.name = null__
+
+The name this file had according to the uploading client.
+
+__file.type = null__
+
+The mime type of this file, according to the uploading client.
+
+__file.lastModifiedDate = 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.hash = null__
+
+If hash calculation was set, you can read the hex digest out of this var.
+
+## License
+
+Formidable is licensed under the MIT license.
+
+## Ports
+
+* [multipart-parser](http://github.com/FooBarWidget/multipart-parser): a C++ parser based on formidable
+
+## Credits
+
+* [Ryan Dahl](http://twitter.com/ryah) for his work on [http-parser](http://github.com/ry/http-parser) which heavily inspired multipart_parser.js
View
3  node_modules/formidable/TODO
@@ -0,0 +1,3 @@
+- Better bufferMaxSize handling approach
+- Add tests for JSON parser pull request and merge it
+- Implement QuerystringParser the same way as MultipartParser
View
70 node_modules/formidable/benchmark/bench-multipart-parser.js
@@ -0,0 +1,70 @@
+require('../test/common');
+var multipartParser = require('../lib/multipart_parser'),
+ MultipartParser = multipartParser.MultipartParser,
+ parser = new MultipartParser(),
+ Buffer = require('buffer').Buffer,
+ boundary = '-----------------------------168072824752491622650073',
+ mb = 100,
+ buffer = createMultipartBuffer(boundary, mb * 1024 * 1024),
+ callbacks =
+ { partBegin: -1,
+ partEnd: -1,
+ headerField: -1,
+ headerValue: -1,
+ partData: -1,
+ end: -1,
+ };
+
+
+parser.initWithBoundary(boundary);
+parser.onHeaderField = function() {
+ callbacks.headerField++;
+};
+
+parser.onHeaderValue = function() {
+ callbacks.headerValue++;
+};
+
+parser.onPartBegin = function() {
+ callbacks.partBegin++;
+};
+
+parser.onPartData = function() {
+ callbacks.partData++;
+};
+
+parser.onPartEnd = function() {
+ callbacks.partEnd++;
+};
+
+parser.onEnd = function() {
+ callbacks.end++;
+};
+
+var start = +new Date(),
+ nparsed = parser.write(buffer),
+ duration = +new Date - start,
+ mbPerSec = (mb / (duration / 1000)).toFixed(2);
+
+console.log(mbPerSec+' mb/sec');
+
+assert.equal(nparsed, buffer.length);
+
+function createMultipartBuffer(boundary, size) {
+ var head =
+ '--'+boundary+'\r\n'
+ + 'content-disposition: form-data; name="field1"\r\n'
+ + '\r\n'
+ , tail = '\r\n--'+boundary+'--\r\n'
+ , buffer = new Buffer(size);
+
+ buffer.write(head, 'ascii', 0);
+ buffer.write(tail, 'ascii', buffer.length - tail.length);
+ return buffer;
+}
+
+process.on('exit', function() {
+ for (var k in callbacks) {
+ assert.equal(0, callbacks[k], k+' count off by '+callbacks[k]);
+ }
+});
View
43 node_modules/formidable/example/post.js
@@ -0,0 +1,43 @@
+require('../test/common');
+var http = require('http'),
+ util = require('util'),
+ formidable = require('formidable'),
+ server;
+
+server = http.createServer(function(req, res) {
+ if (req.url == '/') {
+ res.writeHead(200, {'content-type': 'text/html'});
+ res.end(
+ '<form action="/post" method="post">'+
+ '<input type="text" name="title"><br>'+
+ '<input type="text" name="data[foo][]"><br>'+
+ '<input type="submit" value="Submit">'+
+ '</form>'
+ );
+ } else if (req.url == '/post') {
+ var form = new formidable.IncomingForm(),
+ fields = [];
+
+ form
+ .on('error', function(err) {
+ res.writeHead(200, {'content-type': 'text/plain'});
+ res.end('error:\n\n'+util.inspect(err));
+ })
+ .on('field', function(field, value) {
+ console.log(field, value);
+ fields.push([field, value]);
+ })
+ .on('end', function() {
+ console.log('-> post done');
+ res.writeHead(200, {'content-type': 'text/plain'});
+ res.end('received fields:\n\n '+util.inspect(fields));
+ });
+ form.parse(req);
+ } else {
+ res.writeHead(404, {'content-type': 'text/plain'});
+ res.end('404');
+ }
+});
+server.listen(TEST_PORT);
+
+console.log('listening on http://localhost:'+TEST_PORT+'/');
View
48 node_modules/formidable/example/upload.js
@@ -0,0 +1,48 @@
+require('../test/common');
+var http = require('http'),
+ util = require('util'),
+ formidable = require('formidable'),
+ server;
+
+server = http.createServer(function(req, res) {
+ if (req.url == '/') {
+ res.writeHead(200, {'content-type': 'text/html'});
+ res.end(
+ '<form action="/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>'
+ );
+ } else if (req.url == '/upload') {
+ var form = new formidable.IncomingForm(),
+ files = [],
+ fields = [];
+
+ form.uploadDir = TEST_TMP;
+
+ form
+ .on('field', function(field, value) {
+ console.log(field, value);
+ fields.push([field, value]);
+ })
+ .on('file', function(field, file) {
+ console.log(field, file);
+ files.push([field, file]);
+ })
+ .on('end', function() {
+ console.log('-> 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));
+ });
+ form.parse(req);
+ } else {
+ res.writeHead(404, {'content-type': 'text/plain'});
+ res.end('404');
+ }
+});
+server.listen(TEST_PORT);
+
+console.log('listening on http://localhost:'+TEST_PORT+'/');
View
1  node_modules/formidable/index.js
@@ -0,0 +1 @@
+module.exports = require('./lib/formidable');
View
73 node_modules/formidable/lib/file.js
@@ -0,0 +1,73 @@
+if (global.GENTLY) require = GENTLY.hijack(require);
+
+var util = require('./util'),
+ WriteStream = require('fs').WriteStream,
+ 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);
+ }
+
+ this._backwardsCompatibility();
+}
+module.exports = File;
+util.inherits(File, EventEmitter);
+
+// @todo Next release: Show error messages when accessing these
+File.prototype._backwardsCompatibility = function() {
+ var self = this;
+ this.__defineGetter__('length', function() {
+ return self.size;
+ });
+ this.__defineGetter__('filename', function() {
+ return self.name;
+ });
+ this.__defineGetter__('mime', function() {
+ return self.type;
+ });
+};
+
+File.prototype.open = function() {
+ this._writeStream = new WriteStream(this.path);
+};
+
+File.prototype.write = function(buffer, cb) {
+ var self = this;
+ this._writeStream.write(buffer, function() {
+ if(self.hash) {
+ self.hash.update(buffer);
+ }
+ self.lastModifiedDate = new Date();
+ self.size += buffer.length;
+ self.emit('progress', self.size);
+ cb();
+ });
+};
+
+File.prototype.end = function(cb) {
+ var self = this;
+ this._writeStream.end(function() {
+ if(self.hash) {
+ self.hash = self.hash.digest('hex');
+ }
+ self.emit('end');
+ cb();
+ });
+};
View
384 node_modules/formidable/lib/incoming_form.js
@@ -0,0 +1,384 @@
+if (global.GENTLY) require = GENTLY.hijack(require);
+
+var fs = require('fs');
+var util = require('./util'),
+ path = require('path'),
+ File = require('./file'),
+ MultipartParser = require('./multipart_parser').MultipartParser,
+ QuerystringParser = require('./querystring_parser').QuerystringParser,
+ StringDecoder = require('string_decoder').StringDecoder,
+ EventEmitter = require('events').EventEmitter,
+ Stream = require('stream').Stream;
+
+function IncomingForm(opts) {
+ if (!(this instanceof IncomingForm)) return new IncomingForm;
+ EventEmitter.call(this);
+
+ opts=opts||{};
+
+ this.error = null;
+ this.ended = false;
+
+ this.maxFieldsSize = opts.maxFieldsSize || 2 * 1024 * 1024;
+ this.keepExtensions = opts.keepExtensions || false;
+ this.uploadDir = opts.uploadDir || IncomingForm.UPLOAD_DIR;
+ this.encoding = opts.encoding || 'utf-8';
+ this.headers = null;
+ this.type = null;
+ this.hash = false;
+
+ this.bytesReceived = null;
+ this.bytesExpected = null;
+
+ this._parser = null;
+ this._flushing = 0;
+ this._fieldsSize = 0;
+};
+util.inherits(IncomingForm, EventEmitter);
+exports.IncomingForm = IncomingForm;
+
+IncomingForm.UPLOAD_DIR = (function() {
+ var dirs = [process.env.TMP, '/tmp', process.cwd()];
+ for (var i = 0; i < dirs.length; i++) {
+ var dir = dirs[i];
+ var isDirectory = false;
+
+ try {
+ isDirectory = fs.statSync(dir).isDirectory();
+ } catch (e) {}
+
+ if (isDirectory) return dir;
+ }
+})();
+
+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;
+ };
+
+ this.writeHeaders(req.headers);
+
+ var self = this;
+ req
+ .on('error', function(err) {
+ self._error(err);
+ })
+ .on('aborted', function() {
+ self.emit('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);
+ }
+ });
+
+ if (cb) {
+ var fields = {}, files = {};
+ this
+ .on('field', function(name, value) {
+ fields[name] = value;
+ })
+ .on('file', function(name, file) {
+ files[name] = file;
+ })
+ .on('error', function(err) {
+ cb(err, fields, files);
+ })
+ .on('end', function() {
+ cb(null, fields, files);
+ });
+ }
+
+ return this;
+};
+
+IncomingForm.prototype.writeHeaders = function(headers) {
+ this.headers = headers;
+ this._parseContentLength();
+ this._parseContentType();
+};
+
+IncomingForm.prototype.write = function(buffer) {
+ if (!this._parser) {
+ this._error(new Error('unintialized 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;
+
+ 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();
+
+ part.on('data', function(buffer) {
+ 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();
+ });
+ });
+};
+
+IncomingForm.prototype._parseContentType = function() {
+ if (!this.headers['content-type']) {
+ this._error(new Error('bad content-type header, no content-type'));
+ return;
+ }
+
+ if (this.headers['content-type'].match(/urlencoded/i)) {
+ this._initUrlencoded();
+ return;
+ }
+
+ if (this.headers['content-type'].match(/multipart/i)) {
+ var m;
+ if (m = this.headers['content-type'].match(/boundary=(?:"([^"]+)"|([^;]+))/i)) {
+ this._initMultipart(m[1] || m[2]);
+ } else {
+ this._error(new Error('bad content-type header, no multipart boundary'));
+ }
+ return;
+ }
+
+ this._error(new Error('bad content-type header, unknown content-type: '+this.headers['content-type']));
+};
+
+IncomingForm.prototype._error = function(err) {
+ if (this.error) {
+ return;
+ }
+
+ this.error = err;
+ this.pause();
+ this.emit('error', err);
+};
+
+IncomingForm.prototype._parseContentLength = function() {
+ if (this.headers['content-length']) {
+ this.bytesReceived = 0;
+ this.bytesExpected = parseInt(this.headers['content-length'], 10);
+ 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;
+ 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;
+
+ var m;
+ if (headerField == 'content-disposition') {
+ if (m = headerValue.match(/name="([^"]+)"/i)) {
+ part.name = m[1];
+ }
+
+ part.filename = self._fileName(headerValue);
+ } else if (headerField == 'content-type') {
+ part.mime = headerValue;
+ }
+
+ headerField = '';
+ headerValue = '';
+ };
+
+ parser.onHeadersEnd = function() {
+ self.onPart(part);
+ };
+
+ parser.onPartData = function(b, start, end) {
+ part.emit('data', b.slice(start, end));
+ };
+
+ parser.onPartEnd = function() {
+ part.emit('end');
+ };
+
+ parser.onEnd = function() {
+ self.ended = true;
+ self._maybeEnd();
+ };
+
+ this._parser = parser;
+};
+
+IncomingForm.prototype._fileName = function(headerValue) {
+ var m = headerValue.match(/filename="(.*?)"($|; )/i)
+ if (!m) return;
+
+ var filename = m[1].substr(m[1].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()
+ , 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 name = '';
+ for (var i = 0; i < 32; i++) {
+ name += Math.floor(Math.random() * 16).toString(16);
+ }
+
+ if (this.keepExtensions) {
+ var ext = path.extname(filename);
+ ext = ext.replace(/(\.[a-z0-9]+).*/, '$1')
+
+ name += ext;
+ }
+
+ return path.join(this.uploadDir, name);
+};
+
+IncomingForm.prototype._maybeEnd = function() {
+ if (!this.ended || this._flushing) {
+ return;
+ }
+
+ this.emit('end');
+};
View
3  node_modules/formidable/lib/index.js
@@ -0,0 +1,3 @@
+var IncomingForm = require('./incoming_form').IncomingForm;
+IncomingForm.IncomingForm = IncomingForm;
+module.exports = IncomingForm;
View
312 node_modules/formidable/lib/multipart_parser.js
@@ -0,0 +1,312 @@
+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 (var 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--', 'ascii', 0);
+ this.boundary.write(str, 'ascii', 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 != CR) {
+ return i;
+ }
+ index++;
+ break;
+ } else if (index - 1 == boundary.length - 2) {
+ if (c != LF) {
+ return i;
+ }
+ index = 0;
+ callback('partBegin');
+ state = S.HEADER_FIELD_START;
+ break;
+ }
+
+ if (c != boundary[index+2]) {
+ return i;
+ }
+ 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;
+ } 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() {
+ 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);
+};
View
25 node_modules/formidable/lib/querystring_parser.js
@@ -0,0 +1,25 @@
+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() {
+ 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);
+ for (var field in fields) {
+ this.onField(field, fields[field]);
+ }
+ this.buffer = '';
+
+ this.onEnd();
+};
View
6 node_modules/formidable/lib/util.js
@@ -0,0 +1,6 @@
+// Backwards compatibility ...
+try {
+ module.exports = require('util');
+} catch (e) {
+ module.exports = require('sys');
+}
View
4 node_modules/formidable/node-gently/Makefile
@@ -0,0 +1,4 @@
+test:
+ @find test/simple/test-*.js | xargs -n 1 -t node
+
+.PHONY: test
View
167 node_modules/formidable/node-gently/Readme.md
@@ -0,0 +1,167 @@
+# Gently
+
+## Purpose
+
+A node.js module that helps with stubbing and behavior verification. It allows you to test the most remote and nested corners of your code while keeping being fully unobtrusive.
+
+## Features
+
+* Overwrite and stub individual object functions
+* Verify that all expected calls have been made in the expected order
+* Restore stubbed functions to their original behavior
+* Detect object / class names from obj.constructor.name and obj.toString()
+* Hijack any required module function or class constructor
+
+## Installation
+
+Via [npm](http://github.com/isaacs/npm):
+
+ npm install gently@latest
+
+## Example
+
+Make sure your dog is working properly:
+
+ function Dog() {}
+
+ Dog.prototype.seeCat = function() {
+ this.bark('whuf, whuf');
+ this.run();
+ }
+
+ Dog.prototype.bark = function(bark) {
+ require('sys').puts(bark);
+ }
+
+ var gently = new (require('gently'))
+ , assert = require('assert')
+ , dog = new Dog();
+
+ gently.expect(dog, 'bark', function(bark) {
+ assert.equal(bark, 'whuf, whuf');
+ });
+ gently.expect(dog, 'run');
+
+ dog.seeCat();
+
+You can also easily test event emitters with this, for example a simple sequence of 2 events emitted by `fs.WriteStream`:
+
+ var gently = new (require('gently'))
+ , stream = new (require('fs').WriteStream)('my_file.txt');
+
+ gently.expect(stream, 'emit', function(event) {
+ assert.equal(event, 'open');
+ });
+
+ gently.expect(stream, 'emit', function(event) {
+ assert.equal(event, 'drain');
+ });
+
+For a full read world example, check out this test case: [test-incoming-form.js](http://github.com/felixge/node-formidable/blob/master/test/simple/test-incoming-form.js) (in [node-formdiable](http://github.com/felixge/node-formidable)).
+
+## API
+
+### Gently
+
+#### new Gently()
+
+Creates a new gently instance. It listens to the process `'exit'` event to make sure all expectations have been verified.
+
+#### gently.expect(obj, method, [[count], stubFn])
+
+Creates an expectation for an objects method to be called. You can optionally specify the call `count` you are expecting, as well as `stubFn` function that will run instead of the original function.
+
+Returns a reference to the function that is getting overwritten.
+
+#### gently.expect([count], stubFn)
+
+Returns a function that is supposed to be executed `count` times, delegating any calls to the provided `stubFn` function. Naming your stubFn closure will help to properly diagnose errors that are being thrown:
+
+ childProcess.exec('ls', gently.expect(function lsCallback(code) {
+ assert.equal(0, code);
+ }));
+
+#### gently.restore(obj, method)
+
+Restores an object method that has been previously overwritten using `gently.expect()`.
+
+#### gently.hijack(realRequire)
+
+Returns a new require functions that catches a reference to all required modules into `gently.hijacked`.
+
+To use this function, include a line like this in your `'my-module.js'`.
+
+ if (global.GENTLY) require = GENTLY.hijack(require);
+
+ var sys = require('sys');
+ exports.hello = function() {
+ sys.log('world');
+ };
+
+Now you can write a test for the module above:
+
+ var gently = global.GENTLY = new (require('gently'))
+ , myModule = require('./my-module');
+
+ gently.expect(gently.hijacked.sys, 'log', function(str) {
+ assert.equal(str, 'world');
+ });
+
+ myModule.hello();
+
+#### gently.stub(location, [exportsName])
+
+Returns a stub class that will be used instead of the real class from the module at `location` with the given `exportsName`.
+
+This allows to test an OOP version of the previous example, where `'my-module.js'`.
+
+ if (global.GENTLY) require = GENTLY.hijack(require);
+
+ var World = require('./world');
+
+ exports.hello = function() {
+ var world = new World();
+ world.hello();
+ }
+
+And `world.js` looks like this:
+
+ var sys = require('sys');
+
+ function World() {
+
+ }
+ module.exports = World;
+
+ World.prototype.hello = function() {
+ sys.log('world');
+ };
+
+Testing `'my-module.js'` can now easily be accomplished:
+
+ var gently = global.GENTLY = new (require('gently'))
+ , WorldStub = gently.stub('./world')
+ , myModule = require('./my-module')
+ , WORLD;
+
+ gently.expect(WorldStub, 'new', function() {
+ WORLD = this;
+ });
+
+ gently.expect(WORLD, 'hello');
+
+ myModule.hello();
+
+#### gently.hijacked
+
+An object that holds the references to all hijacked modules.
+
+#### gently.verify([msg])
+
+Verifies that all expectations of this gently instance have been satisfied. If not called manually, this method is called when the process `'exit'` event is fired.
+
+If `msg` is given, it will appear in any error that might be thrown.
+
+## License
+
+Gently is licensed under the MIT license.
View
22 node_modules/formidable/node-gently/example/dog.js
@@ -0,0 +1,22 @@
+require('../test/common');
+function Dog() {}
+
+Dog.prototype.seeCat = function() {
+ this.bark('whuf, whuf');
+ this.run();
+}
+
+Dog.prototype.bark = function(bark) {
+ require('sys').puts(bark);
+}
+
+var gently = new (require('gently'))
+ , assert = require('assert')
+ , dog = new Dog();
+
+gently.expect(dog, 'bark', function(bark) {
+ assert.equal(bark, 'whuf, whuf');
+});
+gently.expect(dog, 'run');
+
+dog.seeCat();
View
11 node_modules/formidable/node-gently/example/event_emitter.js
@@ -0,0 +1,11 @@
+require('../test/common');
+var gently = new (require('gently'))
+ , stream = new (require('fs').WriteStream)('my_file.txt');
+
+gently.expect(stream, 'emit', function(event) {
+ assert.equal(event, 'open');
+});
+
+gently.expect(stream, 'emit', function(event) {
+ assert.equal(event, 'drain');
+});
View
1  node_modules/formidable/node-gently/index.js
@@ -0,0 +1 @@
+module.exports = require('./lib/gently');
View
184 node_modules/formidable/node-gently/lib/gently/gently.js
@@ -0,0 +1,184 @@
+var path = require('path');
+
+function Gently() {
+ this.expectations = [];
+ this.hijacked = {};
+
+ var self = this;
+ process.addListener('exit', function() {
+ self.verify('process exit');
+ });
+};
+module.exports = Gently;
+
+Gently.prototype.stub = function(location, exportsName) {
+ function Stub() {
+ return Stub['new'].apply(this, arguments);
+ };
+
+ Stub['new'] = function () {};
+
+ var stubName = 'require('+JSON.stringify(location)+')';
+ if (exportsName) {
+ stubName += '.'+exportsName;
+ }
+
+ Stub.prototype.toString = Stub.toString = function() {
+ return stubName;
+ };
+
+ var exports = this.hijacked[location] || {};
+ if (exportsName) {
+ exports[exportsName] = Stub;
+ } else {
+ exports = Stub;
+ }
+
+ this.hijacked[location] = exports;
+ return Stub;
+};
+
+Gently.prototype.hijack = function(realRequire) {
+ var self = this;
+ return function(location) {
+ return self.hijacked[location] = (self.hijacked[location])
+ ? self.hijacked[location]
+ : realRequire(location);
+ };
+};
+
+Gently.prototype.expect = function(obj, method, count, stubFn) {
+ if (typeof obj != 'function' && typeof obj != 'object' && typeof obj != 'number') {
+ throw new Error
+ ( 'Bad 1st argument for gently.expect(), '
+ + 'object, function, or number expected, got: '+(typeof obj)
+ );
+ } else if (typeof obj == 'function' && (typeof method != 'string')) {
+ // expect(stubFn) interface
+ stubFn = obj;
+ obj = null;
+ method = null;
+ count = 1;
+ } else if (typeof method == 'function') {
+ // expect(count, stubFn) interface
+ count = obj;
+ stubFn = method;
+ obj = null;
+ method = null;
+ } else if (typeof count == 'function') {
+ // expect(obj, method, stubFn) interface
+ stubFn = count;
+ count = 1;
+ } else if (count === undefined) {
+ // expect(obj, method) interface
+ count = 1;
+ }
+
+ var name = this._name(obj, method, stubFn);
+ this.expectations.push({obj: obj, method: method, stubFn: stubFn, name: name, count: count});
+
+ var self = this;
+ function delegate() {
+ return self._stubFn(this, obj, method, name, Array.prototype.slice.call(arguments));
+ }
+
+ if (!obj) {
+ return delegate;
+ }
+
+ var original = (obj[method])
+ ? obj[method]._original || obj[method]
+ : undefined;
+
+ obj[method] = delegate;
+ return obj[method]._original = original;
+};
+
+Gently.prototype.restore = function(obj, method) {
+ if (!obj[method] || !obj[method]._original) {
+ throw new Error(this._name(obj, method)+' is not gently stubbed');
+ }
+ obj[method] = obj[method]._original;
+};
+
+Gently.prototype.verify = function(msg) {
+ if (!this.expectations.length) {
+ return;
+ }
+
+ var validExpectations = [];
+ for (var i = 0, l = this.expectations.length; i < l; i++) {
+ var expectation = this.expectations[i];
+
+ if (expectation.count > 0) {
+ validExpectations.push(expectation);
+ }
+ }
+
+ this.expectations = []; // reset so that no duplicate verification attempts are made
+
+ if (!validExpectations.length) {
+ return;
+ }
+
+ var expectation = validExpectations[0];
+
+ throw new Error
+ ( 'Expected call to '+expectation.name+' did not happen'
+ + ( (msg)
+ ? ' ('+msg+')'
+ : ''
+ )
+ );
+};
+
+Gently.prototype._stubFn = function(self, obj, method, name, args) {
+ var expectation = this.expectations[0], obj, method;
+
+ if (!expectation) {
+ throw new Error('Unexpected call to '+name+', no call was expected');
+ }
+
+ if (expectation.obj !== obj || expectation.method !== method) {
+ throw new Error('Unexpected call to '+name+', expected call to '+ expectation.name);
+ }
+
+ expectation.count -= 1;
+ if (expectation.count === 0) {
+ this.expectations.shift();
+
+ // autorestore original if its not a closure
+ // and no more expectations on that object
+ var has_more_expectations = this.expectations.reduce(function (memo, expectation) {
+ return memo || (expectation.obj === obj && expectation.method === method);
+ }, false);
+ if (obj !== null && method !== null && !has_more_expectations) {
+ if (typeof obj[method]._original !== 'undefined') {
+ obj[method] = obj[method]._original;
+ delete obj[method]._original;
+ } else {
+ delete obj[method];
+ }
+ }
+ }
+
+ if (expectation.stubFn) {
+ return expectation.stubFn.apply(self, args);
+ }
+};
+
+Gently.prototype._name = function(obj, method, stubFn) {
+ if (obj) {
+ var objectName = obj.toString();
+ if (objectName == '[object Object]' && obj.constructor.name) {
+ objectName = '['+obj.constructor.name+']';
+ }
+ return (objectName)+'.'+method+'()';
+ }
+
+ if (stubFn.name) {
+ return stubFn.name+'()';
+ }
+
+ return '>> '+stubFn.toString()+' <<';
+};
View
1  node_modules/formidable/node-gently/lib/gently/index.js
@@ -0,0 +1 @@
+module.exports = require('./gently');
View
14 node_modules/formidable/node-gently/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "gently",
+ "version": "0.9.2",
+ "directories": {
+ "lib": "./lib/gently"
+ },
+ "main": "./lib/gently/index",
+ "dependencies": {},
+ "devDependencies": {},
+ "engines": {
+ "node": "*"
+ },
+ "optionalDependencies": {}
+}
View
8 node_modules/formidable/node-gently/test/common.js
@@ -0,0 +1,8 @@
+var path = require('path')
+ , sys = require('sys');
+
+require.paths.unshift(path.dirname(__dirname)+'/lib');
+
+global.puts = sys.puts;
+global.p = function() {sys.error(sys.inspect.apply(null, arguments))};;
+global.assert = require('assert');
View
348 node_modules/formidable/node-gently/test/simple/test-gently.js
@@ -0,0 +1,348 @@
+require('../common');
+var Gently = require('gently')
+ , gently;
+
+function test(test) {
+ process.removeAllListeners('exit');
+ gently = new Gently();
+ test();
+}
+
+test(function constructor() {
+ assert.deepEqual(gently.expectations, []);
+ assert.deepEqual(gently.hijacked, {});
+ assert.equal(gently.constructor.name, 'Gently');
+});
+
+test(function expectBadArgs() {
+ var BAD_ARG = 'oh no';
+ try {
+ gently.expect(BAD_ARG);
+ assert.ok(false, 'throw needs to happen');
+ } catch (e) {
+ assert.equal(e.message, 'Bad 1st argument for gently.expect(), object, function, or number expected, got: '+(typeof BAD_ARG));
+ }
+});
+
+test(function expectObjMethod() {
+ var OBJ = {}, NAME = 'foobar';
+ OBJ.foo = function(x) {
+ return x;
+ };
+
+ gently._name = function() {
+ return NAME;
+ };
+
+ var original = OBJ.foo
+ , stubFn = function() {};
+
+ (function testAddOne() {
+ assert.strictEqual(gently.expect(OBJ, 'foo', stubFn), original);
+
+ assert.equal(gently.expectations.length, 1);
+ var expectation = gently.expectations[0];
+ assert.strictEqual(expectation.obj, OBJ);
+ assert.strictEqual(expectation.method, 'foo');
+ assert.strictEqual(expectation.stubFn, stubFn);
+ assert.strictEqual(expectation.name, NAME);
+ assert.strictEqual(OBJ.foo._original, original);
+ })();
+
+ (function testAddTwo() {
+ gently.expect(OBJ, 'foo', 2, stubFn);
+ assert.equal(gently.expectations.length, 2);
+ assert.strictEqual(OBJ.foo._original, original);
+ })();
+
+ (function testAddOneWithoutMock() {
+ gently.expect(OBJ, 'foo');
+ assert.equal(gently.expectations.length, 3);
+ })();
+
+ var stubFnCalled = 0, SELF = {};
+ gently._stubFn = function(self, obj, method, name, args) {
+ stubFnCalled++;
+ assert.strictEqual(self, SELF);
+ assert.strictEqual(obj, OBJ);
+ assert.strictEqual(method, 'foo');
+ assert.strictEqual(name, NAME);
+ assert.deepEqual(args, [1, 2]);
+ return 23;
+ };
+ assert.equal(OBJ.foo.apply(SELF, [1, 2]), 23);
+ assert.equal(stubFnCalled, 1);
+});
+
+test(function expectClosure() {
+ var NAME = 'MY CLOSURE';
+ function closureFn() {};
+
+ gently._name = function() {
+ return NAME;
+ };
+
+ var fn = gently.expect(closureFn);
+ assert.equal(gently.expectations.length, 1);
+ var expectation = gently.expectations[0];
+ assert.strictEqual(expectation.obj, null);
+ assert.strictEqual(expectation.method, null);
+ assert.strictEqual(expectation.stubFn, closureFn);
+ assert.strictEqual(expectation.name, NAME);
+
+ var stubFnCalled = 0, SELF = {};
+ gently._stubFn = function(self, obj, method, name, args) {
+ stubFnCalled++;
+ assert.strictEqual(self, SELF);
+ assert.strictEqual(obj, null);
+ assert.strictEqual(method, null);
+ assert.strictEqual(name, NAME);
+ assert.deepEqual(args, [1, 2]);
+ return 23;
+ };
+ assert.equal(fn.apply(SELF, [1, 2]), 23);
+ assert.equal(stubFnCalled, 1);
+});
+
+test(function expectClosureCount() {
+ var stubFnCalled = 0;
+ function closureFn() {stubFnCalled++};
+
+ var fn = gently.expect(2, closureFn);
+ assert.equal(gently.expectations.length, 1);
+ fn();
+ assert.equal(gently.expectations.length, 1);
+ fn();
+ assert.equal(stubFnCalled, 2);
+});
+
+test(function restore() {
+ var OBJ = {}, NAME = '[my object].myFn()';
+ OBJ.foo = function(x) {
+ return x;
+ };
+
+ gently._name = function() {
+ return NAME;
+ };
+
+ var original = OBJ.foo;
+ gently.expect(OBJ, 'foo');
+ gently.restore(OBJ, 'foo');
+ assert.strictEqual(OBJ.foo, original);
+
+ (function testError() {
+ try {
+ gently.restore(OBJ, 'foo');
+ assert.ok(false, 'throw needs to happen');
+ } catch (e) {
+ assert.equal(e.message, NAME+' is not gently stubbed');
+ }
+ })();
+});
+
+test(function _stubFn() {
+ var OBJ1 = {toString: function() {return '[OBJ 1]'}}
+ , OBJ2 = {toString: function() {return '[OBJ 2]'}, foo: function () {return 'bar';}}
+ , SELF = {};
+
+ gently.expect(OBJ1, 'foo', function(x) {
+ assert.strictEqual(this, SELF);
+ return x * 2;
+ });
+
+ assert.equal(gently._stubFn(SELF, OBJ1, 'foo', 'dummy_name', [5]), 10);
+
+ (function testAutorestore() {
+ assert.equal(OBJ2.foo(), 'bar');
+
+ gently.expect(OBJ2, 'foo', function() {
+ return 'stubbed foo';
+ });
+
+ gently.expect(OBJ2, 'foo', function() {
+ return "didn't restore yet";
+ });
+
+ assert.equal(gently._stubFn(SELF, OBJ2, 'foo', 'dummy_name', []), 'stubbed foo');
+ assert.equal(gently._stubFn(SELF, OBJ2, 'foo', 'dummy_name', []), "didn't restore yet");
+ assert.equal(OBJ2.foo(), 'bar');
+ assert.deepEqual(gently.expectations, []);
+ })();
+
+ (function testNoMoreCallExpected() {
+ try {
+ gently._stubFn(SELF, OBJ1, 'foo', 'dummy_name', [5]);
+ assert.ok(false, 'throw needs to happen');
+ } catch (e) {
+ assert.equal(e.message, 'Unexpected call to dummy_name, no call was expected');
+ }
+ })();
+
+ (function testDifferentCallExpected() {
+ gently.expect(OBJ2, 'bar');
+ try {
+ gently._stubFn(SELF, OBJ1, 'foo', 'dummy_name', [5]);
+ assert.ok(false, 'throw needs to happen');
+ } catch (e) {
+ assert.equal(e.message, 'Unexpected call to dummy_name, expected call to '+gently._name(OBJ2, 'bar'));
+ }
+
+ assert.equal(gently.expectations.length, 1);
+ })();
+
+ (function testNoMockCallback() {
+ OBJ2.bar();
+ assert.equal(gently.expectations.length, 0);
+ })();
+});
+
+test(function stub() {
+ var LOCATION = './my_class';
+
+ (function testRegular() {
+ var Stub = gently.stub(LOCATION);
+ assert.ok(Stub instanceof Function);
+ assert.strictEqual(gently.hijacked[LOCATION], Stub);
+ assert.ok(Stub['new'] instanceof Function);
+ assert.equal(Stub.toString(), 'require('+JSON.stringify(LOCATION)+')');
+
+ (function testConstructor() {
+ var newCalled = 0
+ , STUB
+ , ARGS = ['foo', 'bar'];
+
+ Stub['new'] = function(a, b) {
+ assert.equal(a, ARGS[0]);
+ assert.equal(b, ARGS[1]);
+ newCalled++;
+ STUB = this;
+ };
+
+ var stub = new Stub(ARGS[0], ARGS[1]);
+ assert.strictEqual(stub, STUB);
+ assert.equal(newCalled, 1);
+ assert.equal(stub.toString(), 'require('+JSON.stringify(LOCATION)+')');
+ })();
+
+ (function testUseReturnValueAsInstance() {
+ var R = {};
+
+ Stub['new'] = function() {
+ return R;
+ };
+
+ var stub = new Stub();
+ assert.strictEqual(stub, R);
+
+ })();
+ })();
+
+ var EXPORTS_NAME = 'MyClass';
+ test(function testExportsName() {
+ var Stub = gently.stub(LOCATION, EXPORTS_NAME);
+ assert.strictEqual(gently.hijacked[LOCATION][EXPORTS_NAME], Stub);
+ assert.equal(Stub.toString(), 'require('+JSON.stringify(LOCATION)+').'+EXPORTS_NAME);
+
+ (function testConstructor() {
+ var stub = new Stub();
+ assert.equal(Stub.toString(), 'require('+JSON.stringify(LOCATION)+').'+EXPORTS_NAME);
+ })();
+ });
+});
+
+test(function hijack() {
+ var LOCATION = './foo'
+ , REQUIRE_CALLS = 0
+ , EXPORTS = {}
+ , REQUIRE = function() {
+ REQUIRE_CALLS++;
+ return EXPORTS;
+ };
+
+ var hijackedRequire = gently.hijack(REQUIRE);
+ hijackedRequire(LOCATION);
+ assert.strictEqual(gently.hijacked[LOCATION], EXPORTS);
+
+ assert.equal(REQUIRE_CALLS, 1);
+
+ // make sure we are caching the hijacked module
+ hijackedRequire(LOCATION);
+ assert.equal(REQUIRE_CALLS, 1);
+});
+
+test(function verify() {
+ var OBJ = {toString: function() {return '[OBJ]'}};
+ gently.verify();
+
+ gently.expect(OBJ, 'foo');
+ try {
+ gently.verify();
+ assert.ok(false, 'throw needs to happen');
+ } catch (e) {
+ assert.equal(e.message, 'Expected call to [OBJ].foo() did not happen');
+ }
+
+ try {
+ gently.verify('foo');
+ assert.ok(false, 'throw needs to happen');
+ } catch (e) {
+ assert.equal(e.message, 'Expected call to [OBJ].foo() did not happen (foo)');
+ }
+});
+
+test(function processExit() {
+ var verifyCalled = 0;
+ gently.verify = function(msg) {
+ verifyCalled++;
+ assert.equal(msg, 'process exit');
+ };
+
+ process.emit('exit');
+ assert.equal(verifyCalled, 1);
+});
+
+test(function _name() {
+ (function testNamedClass() {
+ function Foo() {};
+ var foo = new Foo();
+ assert.equal(gently._name(foo, 'bar'), '[Foo].bar()');
+ })();
+
+ (function testToStringPreference() {
+ function Foo() {};
+ Foo.prototype.toString = function() {
+ return '[Superman 123]';
+ };
+ var foo = new Foo();
+ assert.equal(gently._name(foo, 'bar'), '[Superman 123].bar()');
+ })();
+
+ (function testUnamedClass() {
+ var Foo = function() {};
+ var foo = new Foo();
+ assert.equal(gently._name(foo, 'bar'), foo.toString()+'.bar()');
+ })();
+
+ (function testNamedClosure() {
+ function myClosure() {};
+ assert.equal(gently._name(null, null, myClosure), myClosure.name+'()');
+ })();
+
+ (function testUnamedClosure() {
+ var myClosure = function() {2+2 == 5};
+ assert.equal(gently._name(null, null, myClosure), '>> '+myClosure.toString()+' <<');
+ })();
+});
+
+test(function verifyExpectNone() {
+ var OBJ = {toString: function() {return '[OBJ]'}};
+ gently.verify();
+
+ gently.expect(OBJ, 'foo', 0);
+ try {
+ gently.verify();
+ } catch (e) {
+ assert.fail('Exception should not have been thrown');
+ }
+});
View
29 node_modules/formidable/package.json
@@ -0,0 +1,29 @@
+{
+ "name": "formidable",
+ "version": "1.0.11",
+ "dependencies": {},
+ "devDependencies": {
+ "gently": "0.8.0",
+ "findit": "0.1.1",
+ "hashish": "0.0.4",
+ "urun": "0.0.4",
+ "utest": "0.0.3"
+ },
+ "directories": {
+ "lib": "./lib"
+ },
+ "main": "./lib/index",
+ "scripts": {
+ "test": "make test"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "optionalDependencies": {},
+ "_id": "formidable@1.0.11",
+ "_engineSupported": true,
+ "_npmVersion": "1.1.22",
+ "_nodeVersion": "v0.6.18",
+ "_defaultsLoaded": true,
+ "_from": "formidable@>=0.9.11"
+}
View
19 node_modules/formidable/test/common.js
@@ -0,0 +1,19 @@
+var mysql = require('..');
+var path = require('path');
+
+var root = path.join(__dirname, '../');
+exports.dir = {
+ root : root,
+ lib : root + '/lib',
+ fixture : root + '/test/fixture',
+ tmp : root + '/test/tmp',
+};
+
+exports.port = 13532;
+
+exports.formidable = require('..');
+exports.assert = require('assert');
+
+exports.require = function(lib) {
+ return require(exports.dir.lib + '/' + lib);
+};
View
1  node_modules/formidable/test/fixture/file/funkyfilename.txt
@@ -0,0 +1 @@
+I am a text file with a funky name!
View
1  node_modules/formidable/test/fixture/file/plain.txt
@@ -0,0 +1 @@
+I am a plain text file
View
3  node_modules/formidable/test/fixture/http/special-chars-in-filename/info.md
@@ -0,0 +1,3 @@
+* Opera does not allow submitting this file, it shows a warning to the
+ user that the file could not be found instead. Tested in 9.8, 11.51 on OSX.
+ Reported to Opera on 08.09.2011 (tracking email DSK-346009@bugs.opera.com).
View
3  node_modules/formidable/test/fixture/js/no-filename.js
@@ -0,0 +1,3 @@
+module.exports['generic.http'] = [
+ {type: 'file', name: 'upload', filename: '', fixture: 'plain.txt'},
+];
View
21 node_modules/formidable/test/fixture/js/special-chars-in-filename.js
@@ -0,0 +1,21 @@
+var properFilename = 'funkyfilename.txt';
+
+function expect(filename) {
+ return [
+ {type: 'field', name: 'title', value: 'Weird filename'},
+ {type: 'file', name: 'upload', filename: filename, fixture: properFilename},
+ ];
+};
+
+var webkit = " ? % * | \" < > . ? ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt";
+var ffOrIe = " ? % * | \" < > . ☃ ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt";
+
+module.exports = {
+ 'osx-chrome-13.http' : expect(webkit),
+ 'osx-firefox-3.6.http' : expect(ffOrIe),
+ 'osx-safari-5.http' : expect(webkit),
+ 'xp-chrome-12.http' : expect(webkit),
+ 'xp-ie-7.http' : expect(ffOrIe),
+ 'xp-ie-8.http' : expect(ffOrIe),
+ 'xp-safari-5.http' : expect(webkit),
+};
View
72 node_modules/formidable/test/fixture/multipart.js
@@ -0,0 +1,72 @@
+exports['rfc1867'] =
+ { boundary: 'AaB03x',
+ raw:
+ '--AaB03x\r\n'+
+ 'content-disposition: form-data; name="field1"\r\n'+
+ '\r\n'+
+ 'Joe Blow\r\nalmost tricked you!\r\n'+
+ '--AaB03x\r\n'+
+ 'content-disposition: form-data; name="pics"; filename="file1.txt"\r\n'+
+ 'Content-Type: text/plain\r\n'+
+ '\r\n'+
+ '... contents of file1.txt ...\r\r\n'+
+ '--AaB03x--\r\n',
+ parts:
+ [ { headers: {
+ 'content-disposition': 'form-data; name="field1"',
+ },
+ data: 'Joe Blow\r\nalmost tricked you!',
+ },
+ { headers: {
+ 'content-disposition': 'form-data; name="pics"; filename="file1.txt"',
+ 'Content-Type': 'text/plain',
+ },
+ data: '... contents of file1.txt ...\r',
+ }
+ ]
+ };
+
+exports['noTrailing\r\n'] =
+ { boundary: 'AaB03x',
+ raw:
+ '--AaB03x\r\n'+
+ 'content-disposition: form-data; name="field1"\r\n'+
+ '\r\n'+
+ 'Joe Blow\r\nalmost tricked you!\r\n'+
+ '--AaB03x\r\n'+
+ 'content-disposition: form-data; name="pics"; filename="file1.txt"\r\n'+
+ 'Content-Type: text/plain\r\n'+
+ '\r\n'+
+ '... contents of file1.txt ...\r\r\n'+
+ '--AaB03x--',
+ parts:
+ [ { headers: {
+ 'content-disposition': 'form-data; name="field1"',
+ },
+ data: 'Joe Blow\r\nalmost tricked you!',
+ },
+ { headers: {
+ 'content-disposition': 'form-data; name="pics"; filename="file1.txt"',
+ 'Content-Type': 'text/plain',
+ },
+ data: '... contents of file1.txt ...\r',
+ }
+ ]
+ };
+
+exports['emptyHeader'] =
+ { boundary: 'AaB03x',
+ raw:
+ '--AaB03x\r\n'+
+ 'content-disposition: form-data; name="field1"\r\n'+
+ ': foo\r\n'+