pax_global_header00006660000000000000000000000064147016473120014517gustar00rootroot0000000000000052 comment=d04f7381b0111c707baa47190de2d48a02988b5b form-data-4.0.1/000077500000000000000000000000001470164731200133735ustar00rootroot00000000000000form-data-4.0.1/.editorconfig000066400000000000000000000002461470164731200160520ustar00rootroot00000000000000# editorconfig.org root = true [*] indent_style = space indent_size = 2 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true form-data-4.0.1/.eslintrc000066400000000000000000000021271470164731200152210ustar00rootroot00000000000000{ "rules": { "indent": [2, 2, {"SwitchCase": 1}], "quotes": [2, "single"], "linebreak-style": [2, "unix"], "semi": [2, "always"], "curly": [2, "multi-line"], "handle-callback-err": [2, "^err"], "valid-jsdoc": [2, { "requireReturn": false, "requireReturnDescription": false, "prefer": { "return": "returns" } }], "require-jsdoc": [2, { "require": { "FunctionDeclaration": true } }], "no-redeclare": [2, { "builtinGlobals": true }], "no-shadow": [2, { "builtinGlobals": true, "hoist": "all" }], "no-use-before-define": [2, "nofunc"], "no-shadow-restricted-names": 2, "no-extra-semi": 2, "no-unused-vars": 2, "no-undef": 2, "no-irregular-whitespace": 2, "no-console": 2, "key-spacing": 0, "strict": 0, "dot-notation": 0, "eol-last": 0, "no-new": 0, "semi-spacing": 0, "no-multi-spaces": 0, "eqeqeq": 0, "no-mixed-requires": 0 }, "env": { "node": true }, "ignorePatterns": [ "node_modules/*", "index.d.ts", "coverage", ] } form-data-4.0.1/.github/000077500000000000000000000000001470164731200147335ustar00rootroot00000000000000form-data-4.0.1/.github/workflows/000077500000000000000000000000001470164731200167705ustar00rootroot00000000000000form-data-4.0.1/.github/workflows/node-aught.yml000066400000000000000000000003631470164731200215500ustar00rootroot00000000000000name: 'Tests: node.js < 10' on: [pull_request, push] permissions: contents: read jobs: tests: uses: ljharb/actions/.github/workflows/node.yml@main with: range: '>= 6 < 10' type: minors command: npm run ci-test form-data-4.0.1/.github/workflows/node-pretest.yml000066400000000000000000000002451470164731200221250ustar00rootroot00000000000000name: 'Tests: pretest/posttest' on: [pull_request, push] permissions: contents: read jobs: tests: uses: ljharb/actions/.github/workflows/pretest.yml@main form-data-4.0.1/.github/workflows/node-tens.yml000066400000000000000000000003601470164731200214060ustar00rootroot00000000000000name: 'Tests: node.js >= 10' on: [pull_request, push] permissions: contents: read jobs: tests: uses: ljharb/actions/.github/workflows/node.yml@main with: range: '>= 10' type: minors command: npm run ci-test form-data-4.0.1/.github/workflows/rebase.yml000066400000000000000000000007001470164731200207510ustar00rootroot00000000000000name: Automatic Rebase on: [pull_request_target] permissions: contents: read jobs: _: permissions: contents: write # for ljharb/rebase to push code to rebase pull-requests: read # for ljharb/rebase to get info about PR name: "Automatic Rebase" runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: ljharb/rebase@master env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} form-data-4.0.1/.github/workflows/require-allow-edits.yml000066400000000000000000000005151470164731200234120ustar00rootroot00000000000000name: Require “Allow Edits” on: [pull_request_target] permissions: contents: read jobs: _: permissions: pull-requests: read # for ljharb/require-allow-edits to check 'allow edits' on PR name: "Require “Allow Edits”" runs-on: ubuntu-latest steps: - uses: ljharb/require-allow-edits@main form-data-4.0.1/.gitignore000066400000000000000000000002061470164731200153610ustar00rootroot00000000000000*.bak *.iml *.log *.sublime-* *.un~ .DS_Store .idea sftp-config.json yarn.lock package-lock.json coverage/ node_modules/ test/tmp/ form-data-4.0.1/.istanbul.yml000066400000000000000000000004571470164731200160230ustar00rootroot00000000000000verbose: false instrumentation: root: . extensions: - .js default-excludes: true reporting: print: summary reports: - json dir: ./coverage watermarks: statements: [90, 95] lines: [90, 95] functions: [90, 95] branches: [90, 95] form-data-4.0.1/.npmignore000066400000000000000000000001431470164731200153700ustar00rootroot00000000000000.* Makefile appveyor.yml sftp-config.json coverage/ node_modules/ test/ yarn.lock README.md.bak form-data-4.0.1/License000066400000000000000000000021361470164731200147020ustar00rootroot00000000000000Copyright (c) 2012 Felix Geisendörfer (felix@debuggable.com) and contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. form-data-4.0.1/Readme.md000066400000000000000000000274461470164731200151270ustar00rootroot00000000000000# Form-Data [![NPM Module](https://img.shields.io/npm/v/form-data.svg)](https://www.npmjs.com/package/form-data) [![Join the chat at https://gitter.im/form-data/form-data](http://form-data.github.io/images/gitterbadge.svg)](https://gitter.im/form-data/form-data) A library to create readable ```"multipart/form-data"``` streams. Can be used to submit forms and file uploads to other web applications. The API of this library is inspired by the [XMLHttpRequest-2 FormData Interface][xhr2-fd]. [xhr2-fd]: http://dev.w3.org/2006/webapi/XMLHttpRequest-2/Overview.html#the-formdata-interface [![Linux Build](https://img.shields.io/travis/form-data/form-data/master.svg?label=linux:6.x-12.x)](https://travis-ci.org/form-data/form-data) [![MacOS Build](https://img.shields.io/travis/form-data/form-data/master.svg?label=macos:6.x-12.x)](https://travis-ci.org/form-data/form-data) [![Windows Build](https://img.shields.io/travis/form-data/form-data/master.svg?label=windows:6.x-12.x)](https://travis-ci.org/form-data/form-data) [![Coverage Status](https://img.shields.io/coveralls/form-data/form-data/master.svg?label=code+coverage)](https://coveralls.io/github/form-data/form-data?branch=master) [![Dependency Status](https://img.shields.io/david/form-data/form-data.svg)](https://david-dm.org/form-data/form-data) ## Install ``` npm install --save form-data ``` ## Usage In this example we are constructing a form with 3 fields that contain a string, a buffer and a file stream. ``` javascript var FormData = require('form-data'); var fs = require('fs'); var form = new FormData(); form.append('my_field', 'my value'); form.append('my_buffer', new Buffer(10)); form.append('my_file', fs.createReadStream('/foo/bar.jpg')); ``` Also you can use http-response stream: ``` javascript var FormData = require('form-data'); var http = require('http'); var form = new FormData(); http.request('http://nodejs.org/images/logo.png', function(response) { form.append('my_field', 'my value'); form.append('my_buffer', new Buffer(10)); form.append('my_logo', response); }); ``` Or @mikeal's [request](https://github.com/request/request) stream: ``` javascript var FormData = require('form-data'); var request = require('request'); var form = new FormData(); form.append('my_field', 'my value'); form.append('my_buffer', new Buffer(10)); form.append('my_logo', request('http://nodejs.org/images/logo.png')); ``` In order to submit this form to a web application, call ```submit(url, [callback])``` method: ``` javascript form.submit('http://example.org/', function(err, res) { // res – response object (http.IncomingMessage) // res.resume(); }); ``` For more advanced request manipulations ```submit()``` method returns ```http.ClientRequest``` object, or you can choose from one of the alternative submission methods. ### Custom options You can provide custom options, such as `maxDataSize`: ``` javascript var FormData = require('form-data'); var form = new FormData({ maxDataSize: 20971520 }); form.append('my_field', 'my value'); form.append('my_buffer', /* something big */); ``` List of available options could be found in [combined-stream](https://github.com/felixge/node-combined-stream/blob/master/lib/combined_stream.js#L7-L15) ### Alternative submission methods You can use node's http client interface: ``` javascript var http = require('http'); var request = http.request({ method: 'post', host: 'example.org', path: '/upload', headers: form.getHeaders() }); form.pipe(request); request.on('response', function(res) { console.log(res.statusCode); }); ``` Or if you would prefer the `'Content-Length'` header to be set for you: ``` javascript form.submit('example.org/upload', function(err, res) { console.log(res.statusCode); }); ``` To use custom headers and pre-known length in parts: ``` javascript var CRLF = '\r\n'; var form = new FormData(); var options = { header: CRLF + '--' + form.getBoundary() + CRLF + 'X-Custom-Header: 123' + CRLF + CRLF, knownLength: 1 }; form.append('my_buffer', buffer, options); form.submit('http://example.com/', function(err, res) { if (err) throw err; console.log('Done'); }); ``` Form-Data can recognize and fetch all the required information from common types of streams (```fs.readStream```, ```http.response``` and ```mikeal's request```), for some other types of streams you'd need to provide "file"-related information manually: ``` javascript someModule.stream(function(err, stdout, stderr) { if (err) throw err; var form = new FormData(); form.append('file', stdout, { filename: 'unicycle.jpg', // ... or: filepath: 'photos/toys/unicycle.jpg', contentType: 'image/jpeg', knownLength: 19806 }); form.submit('http://example.com/', function(err, res) { if (err) throw err; console.log('Done'); }); }); ``` The `filepath` property overrides `filename` and may contain a relative path. This is typically used when uploading [multiple files from a directory](https://wicg.github.io/entries-api/#dom-htmlinputelement-webkitdirectory). For edge cases, like POST request to URL with query string or to pass HTTP auth credentials, object can be passed to `form.submit()` as first parameter: ``` javascript form.submit({ host: 'example.com', path: '/probably.php?extra=params', auth: 'username:password' }, function(err, res) { console.log(res.statusCode); }); ``` In case you need to also send custom HTTP headers with the POST request, you can use the `headers` key in first parameter of `form.submit()`: ``` javascript form.submit({ host: 'example.com', path: '/surelynot.php', headers: {'x-test-header': 'test-header-value'} }, function(err, res) { console.log(res.statusCode); }); ``` ### Methods - [_Void_ append( **String** _field_, **Mixed** _value_ [, **Mixed** _options_] )](https://github.com/form-data/form-data#void-append-string-field-mixed-value--mixed-options-). - [_Headers_ getHeaders( [**Headers** _userHeaders_] )](https://github.com/form-data/form-data#array-getheaders-array-userheaders-) - [_String_ getBoundary()](https://github.com/form-data/form-data#string-getboundary) - [_Void_ setBoundary()](https://github.com/form-data/form-data#void-setboundary) - [_Buffer_ getBuffer()](https://github.com/form-data/form-data#buffer-getbuffer) - [_Integer_ getLengthSync()](https://github.com/form-data/form-data#integer-getlengthsync) - [_Integer_ getLength( **function** _callback_ )](https://github.com/form-data/form-data#integer-getlength-function-callback-) - [_Boolean_ hasKnownLength()](https://github.com/form-data/form-data#boolean-hasknownlength) - [_Request_ submit( _params_, **function** _callback_ )](https://github.com/form-data/form-data#request-submit-params-function-callback-) - [_String_ toString()](https://github.com/form-data/form-data#string-tostring) #### _Void_ append( **String** _field_, **Mixed** _value_ [, **Mixed** _options_] ) Append data to the form. You can submit about any format (string, integer, boolean, buffer, etc.). However, Arrays are not supported and need to be turned into strings by the user. ```javascript var form = new FormData(); form.append( 'my_string', 'my value' ); form.append( 'my_integer', 1 ); form.append( 'my_boolean', true ); form.append( 'my_buffer', new Buffer(10) ); form.append( 'my_array_as_json', JSON.stringify( ['bird','cute'] ) ) ``` You may provide a string for options, or an object. ```javascript // Set filename by providing a string for options form.append( 'my_file', fs.createReadStream('/foo/bar.jpg'), 'bar.jpg' ); // provide an object. form.append( 'my_file', fs.createReadStream('/foo/bar.jpg'), {filename: 'bar.jpg', contentType: 'image/jpeg', knownLength: 19806} ); ``` #### _Headers_ getHeaders( [**Headers** _userHeaders_] ) This method adds the correct `content-type` header to the provided array of `userHeaders`. #### _String_ getBoundary() Return the boundary of the formData. By default, the boundary consists of 26 `-` followed by 24 numbers for example: ```javascript --------------------------515890814546601021194782 ``` #### _Void_ setBoundary(String _boundary_) Set the boundary string, overriding the default behavior described above. _Note: The boundary must be unique and may not appear in the data._ #### _Buffer_ getBuffer() Return the full formdata request package, as a Buffer. You can insert this Buffer in e.g. Axios to send multipart data. ```javascript var form = new FormData(); form.append( 'my_buffer', Buffer.from([0x4a,0x42,0x20,0x52,0x6f,0x63,0x6b,0x73]) ); form.append( 'my_file', fs.readFileSync('/foo/bar.jpg') ); axios.post( 'https://example.com/path/to/api', form.getBuffer(), form.getHeaders() ) ``` **Note:** Because the output is of type Buffer, you can only append types that are accepted by Buffer: *string, Buffer, ArrayBuffer, Array, or Array-like Object*. A ReadStream for example will result in an error. #### _Integer_ getLengthSync() Same as `getLength` but synchronous. _Note: getLengthSync __doesn't__ calculate streams length._ #### _Integer_ getLength( **function** _callback_ ) Returns the `Content-Length` async. The callback is used to handle errors and continue once the length has been calculated ```javascript this.getLength(function(err, length) { if (err) { this._error(err); return; } // add content length request.setHeader('Content-Length', length); ... }.bind(this)); ``` #### _Boolean_ hasKnownLength() Checks if the length of added values is known. #### _Request_ submit( _params_, **function** _callback_ ) Submit the form to a web application. ```javascript var form = new FormData(); form.append( 'my_string', 'Hello World' ); form.submit( 'http://example.com/', function(err, res) { // res – response object (http.IncomingMessage) // res.resume(); } ); ``` #### _String_ toString() Returns the form data as a string. Don't use this if you are sending files or buffers, use `getBuffer()` instead. ### Integration with other libraries #### Request Form submission using [request](https://github.com/request/request): ```javascript var formData = { my_field: 'my_value', my_file: fs.createReadStream(__dirname + '/unicycle.jpg'), }; request.post({url:'http://service.com/upload', formData: formData}, function(err, httpResponse, body) { if (err) { return console.error('upload failed:', err); } console.log('Upload successful! Server responded with:', body); }); ``` For more details see [request readme](https://github.com/request/request#multipartform-data-multipart-form-uploads). #### node-fetch You can also submit a form using [node-fetch](https://github.com/bitinn/node-fetch): ```javascript var form = new FormData(); form.append('a', 1); fetch('http://example.com', { method: 'POST', body: form }) .then(function(res) { return res.json(); }).then(function(json) { console.log(json); }); ``` #### axios In Node.js you can post a file using [axios](https://github.com/axios/axios): ```javascript const form = new FormData(); const stream = fs.createReadStream(PATH_TO_FILE); form.append('image', stream); // In Node.js environment you need to set boundary in the header field 'Content-Type' by calling method `getHeaders` const formHeaders = form.getHeaders(); axios.post('http://example.com', form, { headers: { ...formHeaders, }, }) .then(response => response) .catch(error => error) ``` ## Notes - ```getLengthSync()``` method DOESN'T calculate length for streams, use ```knownLength``` options as workaround. - ```getLength(cb)``` will send an error as first parameter of callback if stream length cannot be calculated (e.g. send in custom streams w/o using ```knownLength```). - ```submit``` will not add `content-length` if form length is unknown or not calculable. - Starting version `2.x` FormData has dropped support for `node@0.10.x`. - Starting version `3.x` FormData has dropped support for `node@4.x`. ## License Form-Data is released under the [MIT](License) license. form-data-4.0.1/index.d.ts000066400000000000000000000034411470164731200152760ustar00rootroot00000000000000// Definitions by: Carlos Ballesteros Velasco // Leon Yu // BendingBender // Maple Miao /// import * as stream from 'stream'; import * as http from 'http'; export = FormData; // Extracted because @types/node doesn't export interfaces. interface ReadableOptions { highWaterMark?: number; encoding?: string; objectMode?: boolean; read?(this: stream.Readable, size: number): void; destroy?(this: stream.Readable, error: Error | null, callback: (error: Error | null) => void): void; autoDestroy?: boolean; } interface Options extends ReadableOptions { writable?: boolean; readable?: boolean; dataSize?: number; maxDataSize?: number; pauseStreams?: boolean; } declare class FormData extends stream.Readable { constructor(options?: Options); append(key: string, value: any, options?: FormData.AppendOptions | string): void; getHeaders(userHeaders?: FormData.Headers): FormData.Headers; submit( params: string | FormData.SubmitOptions, callback?: (error: Error | null, response: http.IncomingMessage) => void ): http.ClientRequest; getBuffer(): Buffer; setBoundary(boundary: string): void; getBoundary(): string; getLength(callback: (err: Error | null, length: number) => void): void; getLengthSync(): number; hasKnownLength(): boolean; } declare namespace FormData { interface Headers { [key: string]: any; } interface AppendOptions { header?: string | Headers; knownLength?: number; filename?: string; filepath?: string; contentType?: string; } interface SubmitOptions extends http.RequestOptions { protocol?: 'https:' | 'http:'; } } form-data-4.0.1/lib/000077500000000000000000000000001470164731200141415ustar00rootroot00000000000000form-data-4.0.1/lib/browser.js000066400000000000000000000001451470164731200161620ustar00rootroot00000000000000/* eslint-env browser */ module.exports = typeof self == 'object' ? self.FormData : window.FormData; form-data-4.0.1/lib/form_data.js000066400000000000000000000326241470164731200164420ustar00rootroot00000000000000var CombinedStream = require('combined-stream'); var util = require('util'); var path = require('path'); var http = require('http'); var https = require('https'); var parseUrl = require('url').parse; var fs = require('fs'); var Stream = require('stream').Stream; var mime = require('mime-types'); var asynckit = require('asynckit'); var populate = require('./populate.js'); // Public API module.exports = FormData; // make it a Stream util.inherits(FormData, CombinedStream); /** * Create readable "multipart/form-data" streams. * Can be used to submit forms * and file uploads to other web applications. * * @constructor * @param {Object} options - Properties to be added/overriden for FormData and CombinedStream */ function FormData(options) { if (!(this instanceof FormData)) { return new FormData(options); } this._overheadLength = 0; this._valueLength = 0; this._valuesToMeasure = []; CombinedStream.call(this); options = options || {}; for (var option in options) { this[option] = options[option]; } } FormData.LINE_BREAK = '\r\n'; FormData.DEFAULT_CONTENT_TYPE = 'application/octet-stream'; FormData.prototype.append = function(field, value, options) { options = options || {}; // allow filename as single option if (typeof options == 'string') { options = {filename: options}; } var append = CombinedStream.prototype.append.bind(this); // all that streamy business can't handle numbers if (typeof value == 'number') { value = '' + value; } // https://github.com/felixge/node-form-data/issues/38 if (Array.isArray(value)) { // Please convert your array into string // the way web server expects it this._error(new Error('Arrays are not supported.')); return; } var header = this._multiPartHeader(field, value, options); var footer = this._multiPartFooter(); append(header); append(value); append(footer); // pass along options.knownLength this._trackLength(header, value, options); }; FormData.prototype._trackLength = function(header, value, options) { var valueLength = 0; // used w/ getLengthSync(), when length is known. // e.g. for streaming directly from a remote server, // w/ a known file a size, and not wanting to wait for // incoming file to finish to get its size. if (options.knownLength != null) { valueLength += +options.knownLength; } else if (Buffer.isBuffer(value)) { valueLength = value.length; } else if (typeof value === 'string') { valueLength = Buffer.byteLength(value); } this._valueLength += valueLength; // @check why add CRLF? does this account for custom/multiple CRLFs? this._overheadLength += Buffer.byteLength(header) + FormData.LINE_BREAK.length; // empty or either doesn't have path or not an http response or not a stream if (!value || ( !value.path && !(value.readable && value.hasOwnProperty('httpVersion')) && !(value instanceof Stream))) { return; } // no need to bother with the length if (!options.knownLength) { this._valuesToMeasure.push(value); } }; FormData.prototype._lengthRetriever = function(value, callback) { if (value.hasOwnProperty('fd')) { // take read range into a account // `end` = Infinity –> read file till the end // // TODO: Looks like there is bug in Node fs.createReadStream // it doesn't respect `end` options without `start` options // Fix it when node fixes it. // https://github.com/joyent/node/issues/7819 if (value.end != undefined && value.end != Infinity && value.start != undefined) { // when end specified // no need to calculate range // inclusive, starts with 0 callback(null, value.end + 1 - (value.start ? value.start : 0)); // not that fast snoopy } else { // still need to fetch file size from fs fs.stat(value.path, function(err, stat) { var fileSize; if (err) { callback(err); return; } // update final size based on the range options fileSize = stat.size - (value.start ? value.start : 0); callback(null, fileSize); }); } // or http response } else if (value.hasOwnProperty('httpVersion')) { callback(null, +value.headers['content-length']); // or request stream http://github.com/mikeal/request } else if (value.hasOwnProperty('httpModule')) { // wait till response come back value.on('response', function(response) { value.pause(); callback(null, +response.headers['content-length']); }); value.resume(); // something else } else { callback('Unknown stream'); } }; FormData.prototype._multiPartHeader = function(field, value, options) { // custom header specified (as string)? // it becomes responsible for boundary // (e.g. to handle extra CRLFs on .NET servers) if (typeof options.header == 'string') { return options.header; } var contentDisposition = this._getContentDisposition(value, options); var contentType = this._getContentType(value, options); var contents = ''; var headers = { // add custom disposition as third element or keep it two elements if not 'Content-Disposition': ['form-data', 'name="' + field + '"'].concat(contentDisposition || []), // if no content type. allow it to be empty array 'Content-Type': [].concat(contentType || []) }; // allow custom headers. if (typeof options.header == 'object') { populate(headers, options.header); } var header; for (var prop in headers) { if (!headers.hasOwnProperty(prop)) continue; header = headers[prop]; // skip nullish headers. if (header == null) { continue; } // convert all headers to arrays. if (!Array.isArray(header)) { header = [header]; } // add non-empty headers. if (header.length) { contents += prop + ': ' + header.join('; ') + FormData.LINE_BREAK; } } return '--' + this.getBoundary() + FormData.LINE_BREAK + contents + FormData.LINE_BREAK; }; FormData.prototype._getContentDisposition = function(value, options) { var filename , contentDisposition ; if (typeof options.filepath === 'string') { // custom filepath for relative paths filename = path.normalize(options.filepath).replace(/\\/g, '/'); } else if (options.filename || value.name || value.path) { // custom filename take precedence // formidable and the browser add a name property // fs- and request- streams have path property filename = path.basename(options.filename || value.name || value.path); } else if (value.readable && value.hasOwnProperty('httpVersion')) { // or try http response filename = path.basename(value.client._httpMessage.path || ''); } if (filename) { contentDisposition = 'filename="' + filename + '"'; } return contentDisposition; }; FormData.prototype._getContentType = function(value, options) { // use custom content-type above all var contentType = options.contentType; // or try `name` from formidable, browser if (!contentType && value.name) { contentType = mime.lookup(value.name); } // or try `path` from fs-, request- streams if (!contentType && value.path) { contentType = mime.lookup(value.path); } // or if it's http-reponse if (!contentType && value.readable && value.hasOwnProperty('httpVersion')) { contentType = value.headers['content-type']; } // or guess it from the filepath or filename if (!contentType && (options.filepath || options.filename)) { contentType = mime.lookup(options.filepath || options.filename); } // fallback to the default content type if `value` is not simple value if (!contentType && typeof value == 'object') { contentType = FormData.DEFAULT_CONTENT_TYPE; } return contentType; }; FormData.prototype._multiPartFooter = function() { return function(next) { var footer = FormData.LINE_BREAK; var lastPart = (this._streams.length === 0); if (lastPart) { footer += this._lastBoundary(); } next(footer); }.bind(this); }; FormData.prototype._lastBoundary = function() { return '--' + this.getBoundary() + '--' + FormData.LINE_BREAK; }; FormData.prototype.getHeaders = function(userHeaders) { var header; var formHeaders = { 'content-type': 'multipart/form-data; boundary=' + this.getBoundary() }; for (header in userHeaders) { if (userHeaders.hasOwnProperty(header)) { formHeaders[header.toLowerCase()] = userHeaders[header]; } } return formHeaders; }; FormData.prototype.setBoundary = function(boundary) { this._boundary = boundary; }; FormData.prototype.getBoundary = function() { if (!this._boundary) { this._generateBoundary(); } return this._boundary; }; FormData.prototype.getBuffer = function() { var dataBuffer = new Buffer.alloc( 0 ); var boundary = this.getBoundary(); // Create the form content. Add Line breaks to the end of data. for (var i = 0, len = this._streams.length; i < len; i++) { if (typeof this._streams[i] !== 'function') { // Add content to the buffer. if(Buffer.isBuffer(this._streams[i])) { dataBuffer = Buffer.concat( [dataBuffer, this._streams[i]]); }else { dataBuffer = Buffer.concat( [dataBuffer, Buffer.from(this._streams[i])]); } // Add break after content. if (typeof this._streams[i] !== 'string' || this._streams[i].substring( 2, boundary.length + 2 ) !== boundary) { dataBuffer = Buffer.concat( [dataBuffer, Buffer.from(FormData.LINE_BREAK)] ); } } } // Add the footer and return the Buffer object. return Buffer.concat( [dataBuffer, Buffer.from(this._lastBoundary())] ); }; FormData.prototype._generateBoundary = function() { // This generates a 50 character boundary similar to those used by Firefox. // They are optimized for boyer-moore parsing. var boundary = '--------------------------'; for (var i = 0; i < 24; i++) { boundary += Math.floor(Math.random() * 10).toString(16); } this._boundary = boundary; }; // Note: getLengthSync DOESN'T calculate streams length // As workaround one can calculate file size manually // and add it as knownLength option FormData.prototype.getLengthSync = function() { var knownLength = this._overheadLength + this._valueLength; // Don't get confused, there are 3 "internal" streams for each keyval pair // so it basically checks if there is any value added to the form if (this._streams.length) { knownLength += this._lastBoundary().length; } // https://github.com/form-data/form-data/issues/40 if (!this.hasKnownLength()) { // Some async length retrievers are present // therefore synchronous length calculation is false. // Please use getLength(callback) to get proper length this._error(new Error('Cannot calculate proper length in synchronous way.')); } return knownLength; }; // Public API to check if length of added values is known // https://github.com/form-data/form-data/issues/196 // https://github.com/form-data/form-data/issues/262 FormData.prototype.hasKnownLength = function() { var hasKnownLength = true; if (this._valuesToMeasure.length) { hasKnownLength = false; } return hasKnownLength; }; FormData.prototype.getLength = function(cb) { var knownLength = this._overheadLength + this._valueLength; if (this._streams.length) { knownLength += this._lastBoundary().length; } if (!this._valuesToMeasure.length) { process.nextTick(cb.bind(this, null, knownLength)); return; } asynckit.parallel(this._valuesToMeasure, this._lengthRetriever, function(err, values) { if (err) { cb(err); return; } values.forEach(function(length) { knownLength += length; }); cb(null, knownLength); }); }; FormData.prototype.submit = function(params, cb) { var request , options , defaults = {method: 'post'} ; // parse provided url if it's string // or treat it as options object if (typeof params == 'string') { params = parseUrl(params); options = populate({ port: params.port, path: params.pathname, host: params.hostname, protocol: params.protocol }, defaults); // use custom params } else { options = populate(params, defaults); // if no port provided use default one if (!options.port) { options.port = options.protocol == 'https:' ? 443 : 80; } } // put that good code in getHeaders to some use options.headers = this.getHeaders(params.headers); // https if specified, fallback to http in any other case if (options.protocol == 'https:') { request = https.request(options); } else { request = http.request(options); } // get content length and fire away this.getLength(function(err, length) { if (err && err !== 'Unknown stream') { this._error(err); return; } // add content length if (length) { request.setHeader('Content-Length', length); } this.pipe(request); if (cb) { var onResponse; var callback = function (error, responce) { request.removeListener('error', callback); request.removeListener('response', onResponse); return cb.call(this, error, responce); }; onResponse = callback.bind(this, null); request.on('error', callback); request.on('response', onResponse); } }.bind(this)); return request; }; FormData.prototype._error = function(err) { if (!this.error) { this.error = err; this.pause(); this.emit('error', err); } }; FormData.prototype.toString = function () { return '[object FormData]'; }; form-data-4.0.1/lib/populate.js000066400000000000000000000002611470164731200163270ustar00rootroot00000000000000// populates missing values module.exports = function(dst, src) { Object.keys(src).forEach(function(prop) { dst[prop] = dst[prop] || src[prop]; }); return dst; }; form-data-4.0.1/package.json000066400000000000000000000045671470164731200156750ustar00rootroot00000000000000{ "author": "Felix Geisendörfer (http://debuggable.com/)", "name": "form-data", "description": "A library to create readable \"multipart/form-data\" streams. Can be used to submit forms and file uploads to other web applications.", "version": "4.0.1", "repository": { "type": "git", "url": "git://github.com/form-data/form-data.git" }, "main": "./lib/form_data", "browser": "./lib/browser", "typings": "./index.d.ts", "scripts": { "pretest": "npm run lint", "pretests-only": "rimraf coverage test/tmp", "tests-only": "istanbul cover test/run.js", "posttests-only": "istanbul report lcov text", "test": "npm run tests-only", "posttest": "npx npm@'>=10.2' audit --production", "lint": "eslint --ext=js,mjs .", "report": "istanbul report lcov text", "ci-lint": "is-node-modern 8 && npm run lint || is-node-not-modern 8", "ci-test": "npm run tests-only && npm run browser && npm run report", "predebug": "rimraf coverage test/tmp", "debug": "verbose=1 ./test/run.js", "browser": "browserify -t browserify-istanbul test/run-browser.js | obake --coverage", "check": "istanbul check-coverage coverage/coverage*.json", "files": "pkgfiles --sort=name", "get-version": "node -e \"console.log(require('./package.json').version)\"", "update-readme": "sed -i.bak 's/\\/master\\.svg/\\/v'$(npm --silent run get-version)'.svg/g' README.md", "restore-readme": "mv README.md.bak README.md", "prepublish": "in-publish && npm run update-readme || not-in-publish", "postpublish": "npm run restore-readme" }, "pre-commit": [ "lint", "ci-test", "check" ], "engines": { "node": ">= 6" }, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "mime-types": "^2.1.12" }, "devDependencies": { "@types/node": "^12.0.10", "browserify": "^13.1.1", "browserify-istanbul": "^2.0.0", "coveralls": "^3.0.4", "cross-spawn": "^6.0.5", "eslint": "^6.0.1", "fake": "^0.2.2", "far": "^0.0.7", "formidable": "^1.0.17", "in-publish": "^2.0.0", "is-node-modern": "^1.0.0", "istanbul": "^0.4.5", "obake": "^0.1.2", "puppeteer": "^1.19.0", "pkgfiles": "^2.3.0", "pre-commit": "^1.1.3", "request": "^2.88.0", "rimraf": "^2.7.1", "tape": "^4.6.2", "typescript": "^3.5.2" }, "license": "MIT" } form-data-4.0.1/test/000077500000000000000000000000001470164731200143525ustar00rootroot00000000000000form-data-4.0.1/test/common.js000066400000000000000000000063001470164731200161770ustar00rootroot00000000000000var fs = require('fs'); var path = require('path'); var assert = require('assert'); var fake = require('fake'); var mime = require('mime-types'); var http = require('http'); var IncomingForm = require('formidable').IncomingForm; var common = module.exports; var rootDir = path.join(__dirname, '..'); common.dir = { lib: path.join(rootDir, '/lib'), fixture: path.join(rootDir, '/test/fixture'), tmp: path.join(rootDir, '/test/tmp') }; common.defaultTypeValue = function () { return new Buffer([1, 2, 3]); }; common.assert = assert; common.fake = fake; common.port = 8432; common.staticPort = 9432; common.httpsPort = 9443; // store server cert in common for later reuse, because self-signed common.httpsServerKey = fs.readFileSync(path.join(__dirname, './fixture/key.pem')); common.httpsServerCert = fs.readFileSync(path.join(__dirname, './fixture/cert.pem')); common.testFields = function (FIELDS, callback) { var fieldsPassed = Object.keys(FIELDS).length; return http.createServer(function (req, res) { var incomingForm = new IncomingForm({uploadDir: common.dir.tmp}); incomingForm.parse(req); common.actions.checkForm(incomingForm, FIELDS, function (fieldsChecked) { // keep track of number of the processed fields callback(fieldsPassed - fieldsChecked); // finish it common.actions.formOnEnd(res); }); }); }; // Actions common.actions = {}; // generic form field population common.actions.populateFields = function(form, fields) { var field; for (var name in fields) { if (!fields.hasOwnProperty(name)) { continue; } field = fields[name]; // important to append ReadStreams within the same tick if ((typeof field.value == 'function')) { field.value = field.value(); } form.append(name, field.value); } }; // generic form submit common.actions.submit = function(form, server) { return form.submit('http://localhost:' + common.port + '/', function(err, res) { if (err) { throw err; } assert.strictEqual(res.statusCode, 200); // unstuck new streams res.resume(); server.close(); }); }; common.actions.checkForm = function(form, fields, callback) { var fieldChecked = 0; form .on('field', function(name, value) { fieldChecked++; common.actions.formOnField(fields, name, value); }) .on('file', function(name, file) { fieldChecked++; common.actions.formOnFile(fields, name, file); }) .on('end', function() { callback(fieldChecked); }); }; common.actions.basicFormOnField = function(name, value) { assert.strictEqual(name, 'my_field'); assert.strictEqual(value, 'my_value'); }; common.actions.formOnField = function(FIELDS, name, value) { assert.ok(name in FIELDS); var field = FIELDS[name]; assert.strictEqual(value, field.value + ''); }; common.actions.formOnFile = function(FIELDS, name, file) { assert.ok(name in FIELDS); var field = FIELDS[name]; assert.strictEqual(file.name, path.basename(field.value.path || field.name)); assert.strictEqual(file.type, field.type ? field.type : mime.lookup(file.name)); }; // after form has finished parsing common.actions.formOnEnd = function(res) { res.writeHead(200); res.end('done'); }; form-data-4.0.1/test/fixture/000077500000000000000000000000001470164731200160405ustar00rootroot00000000000000form-data-4.0.1/test/fixture/cert.pem000066400000000000000000000036601470164731200175050ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIFfzCCA2egAwIBAgIJALeHtgIY/UKcMA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNV BAYTAk5MMQswCQYDVQQIDAJPVjESMBAGA1UEBwwJUGFsbyBBbHRvMREwDwYDVQQK DAhGb3JtRGF0YTESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTE5MDMyMDExNTI1NVoY DzIwNTkwMzEwMTE1MjU1WjBVMQswCQYDVQQGEwJOTDELMAkGA1UECAwCT1YxEjAQ BgNVBAcMCVBhbG8gQWx0bzERMA8GA1UECgwIRm9ybURhdGExEjAQBgNVBAMMCWxv Y2FsaG9zdDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALHtx1z8nZIr kQo8UbeLxv+S38xHwYSSCHzJBAXGx6PMTFcXdvDvvFrbf772/Gq76tfWtthao+nu 0n14aWepVSucltRUpfwTXau5knoN5J9EL+FbLwfFIUGLEdjnky7UOdtFLN2SYM0B O5/+Nk+ywtBMzXMXHb0sJ0lrNPM8AOD57sIJ/KcqjG33bCgx0GLxuLmLwNupvDNp p3lIvghgTKIOWRKyVOGPpM25DNvI8OT+ldj0KV7y3xJPtNdMcu0bZ+fapJSb48UN koiQb8jxRnl295MAb82piohsLeZE0HGpwT/CWwvUxqgBahDJDmYVBaK9JVEvcMiz wt+wy+xHd9TrgyfrHmBuHKWpgQPbumfWh2OzEeyF1N9dbAbgQ7Tmo/L6zz576Q2x 7Ee5tuyX1apEEpXM5fHxMcM04kHuyz3wqUe4U//LOPmoJ4oAUpkMC/8QMluAFK4i 1yZAw1kB0B4UbLkTIqJYvI3uEzzWe4Q33kVn1AyNBOLXw79t4ZFfhEf6oU0Zjyqp OBNs81imLtgQU4L+D1Rt6aIL8BMhpSM9dGG2ujXqwhZnqtgVuSMY8gI7N+Hjg433 hdxbvpzl0HjnruWvoXDKOWv08sYJhtMqclRQRGDSmxdwps+f5Iocap9AN2wfDmeO cHJohZyw+8l/L2MAp19xJGfN2wRsVrOrAgMBAAGjUDBOMB0GA1UdDgQWBBR+hImn BxHZ03bONEdB6JPPyo0kGDAfBgNVHSMEGDAWgBR+hImnBxHZ03bONEdB6JPPyo0k GDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQAhpfrm79WQuMbudbIz pOjp26OO51cM4CKzH2vUXdgzjNEDHL2JwN0MiLHK0vwT5SkH1uoHRvECHIG8FHrA t9ky7W0Xw4vza9pC5GJEcCHVFGEaPJVXA7+fg5JCjejeWV1PU1LsMLBibbikVFUN JXTbKLL1EWbDLSX4ICJEyc3fptYB/w/lpDZqiKF2uIm2LSubo+fRg3D1mCexsXv1 nl2g9eZkx6uhUl7yq8o5lB6Ejzr1t5npA8w0RlYpvMwagqSfblM7UgvcrEW6Cusl ICELrCY/mfZwKvTgIRrj4Te19ARgXwkrG0KxcgDb+UCBaIca79t53AbpHVVrVPh6 hXHOQrRMjf0taFILPJYn6RcC08zx7FCet4x5WqX4900yRZX7Lr0VLDZI8/c1gf0j PsTA9JqARiQG8qeM5abLxSiXGPypYNkBlbf9H8WDpJgxRNK9RszogNhKdPkYzv0b HgHrAOels9u3roR+wNVIy2PX+LFeSnfUCJjJZEeqs5ewpP9vgBxVIzszO2lZu1oq uUEoFRPnIDA3TsYLzjw9MNMH0CeKUv+83QX7C9UuSyNdKZIgq2z/ABclgBtyFDSX 6EAL5WP55CCCiIG93A0y84rALIS7mPVBzVnxzRY96M2Ifs8GCwMi2Q5ykcVIPkyR HVi0h+PsbIWC9+H9Ljl2vgu0cw== -----END CERTIFICATE----- form-data-4.0.1/test/fixture/key.pem000066400000000000000000000062531470164731200173410ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIJKQIBAAKCAgEAse3HXPydkiuRCjxRt4vG/5LfzEfBhJIIfMkEBcbHo8xMVxd2 8O+8Wtt/vvb8arvq19a22Fqj6e7SfXhpZ6lVK5yW1FSl/BNdq7mSeg3kn0Qv4Vsv B8UhQYsR2OeTLtQ520Us3ZJgzQE7n/42T7LC0EzNcxcdvSwnSWs08zwA4Pnuwgn8 pyqMbfdsKDHQYvG4uYvA26m8M2mneUi+CGBMog5ZErJU4Y+kzbkM28jw5P6V2PQp XvLfEk+010xy7Rtn59qklJvjxQ2SiJBvyPFGeXb3kwBvzamKiGwt5kTQcanBP8Jb C9TGqAFqEMkOZhUFor0lUS9wyLPC37DL7Ed31OuDJ+seYG4cpamBA9u6Z9aHY7MR 7IXU311sBuBDtOaj8vrPPnvpDbHsR7m27JfVqkQSlczl8fExwzTiQe7LPfCpR7hT /8s4+agnigBSmQwL/xAyW4AUriLXJkDDWQHQHhRsuRMioli8je4TPNZ7hDfeRWfU DI0E4tfDv23hkV+ER/qhTRmPKqk4E2zzWKYu2BBTgv4PVG3pogvwEyGlIz10Yba6 NerCFmeq2BW5IxjyAjs34eODjfeF3Fu+nOXQeOeu5a+hcMo5a/TyxgmG0ypyVFBE YNKbF3Cmz5/kihxqn0A3bB8OZ45wcmiFnLD7yX8vYwCnX3EkZ83bBGxWs6sCAwEA AQKCAgEApJk2K9RZpEX/V/uzENwSzI0/0Ye0AwLhLSb8PKfGOcYd/Rds5bixg0+5 Xpy3p7mNp/wui/lV12widwX0ZHwmmUCz21svbgEwT1NNqPG/RILc1Fn5KPP5LtwL N6AK7XBQ0YKt3Y+zUxLH6NtPvOy/Adl62fRRg5YcBfRSOI2Sto0fjYuVmcNnw7b2 7Dwg7dd1rtgVImBkBR/BWRatDaygV+50AjLNCRlMOS/uMEg0aXMGhnxg5UBCknr/ 7YgAbU5EEh2W0Q9hZwKGQyVy8+4X5vfiUbA+vYAQ8uE4mOOh/PQwHN6cQVamK/ea +ko0ssTRwNm/ctozOMfrB+pSy5LVy6rePVKRWnvI+6w5HZgcGXVFegL8Tcky/SBd LNUBKI1LTPDFgxTfMU+QaAt6ABa5xG7sfG9E2EyDIctKX3oNwqARUSIxAlTNFXin IcsX2mjWvc0u1ps17eHyboYhG3JP3/cHL6avTU5u3kbX8I7gb+ioPke2eqm/G/JM kRQ7pRvB1L83x2TrIWlXLZ49r4oMACDBvP4G4reYM/ExPsc6Xnwl+qyuFiyo/ENW NbdS/v6k+Cn6+kIAD/0K3S5x1y/tu3VGnioVV2b7zNGnKqMWtlqUB2sr0IdvgFk4 cDtOJYUd4iUt5/4jJ208GCV7NVvHLezZZ5C/y7W9st1Y5jD8LsECggEBAOxodq+9 J40/3g8YtdBQCOH0W+C/qKqf9DhVCKKDs3p1aTjcjYpG0A900+NjHKEHzX6PkoUh PY+hNqhg+FJUBFKK7XDySRzPKcRJVcAhL/cZ3oTZYzDeJyCcv9/XxIrCni8MDNrn VJl+G1Katw2E+UjJmujuCioOcdDNMzQ/uKyfvCoZm8mhKNLkbp5wm1/y/1Oqjpnl C1FiioAxY4YpkUGKnHI7nsb6FVH0zA3YIW4GFWJttiSVbotKkCPVENA/O0vUHQq2 OH0dRd7EC2ikvQ4X/y7MkCRfuhi4tp9Za8QWWCwGe6iKZ15rKo4Md+VwZy7TN8Db istpNMHeMyiosKECggEBAMCspMWk3w06CFef52GJGJBlE1A5ON36R1rxXYBAOH21 zmULxPyV+2E4mgOCJexq1JkWNYaAYaoMBfUxm/LuAJWivs+ozVYGfQHIOmXXuc4x OMtxaTHTeYBWU2iYGiLiKq1V3lzla+Wo7cE07Bf/Erno67V0aKFWyMhVCcZYaBci 2hIamLIy3fKmKBisk8SVJOmhb3Q5WTW/0LlHq2dnzTC495oIEYkREkgn5AUbHrhj LdLRhon7fLTrSKp7fyW5HvUUsJkdXE0dAtFtTTeUdztxGs7jBcPsRv+8GL3M47sX vgCTxo3WCtXO3Pln80Gc5oAcghberIXE5EzrKBA8JMsCggEBAIT+285QBqEzDfTG PPp9HBIpy0pr6DJdHCJYzCvJFb5NsS1Y/pOM9N3NJqrkhiWdYyDRGmek5KIZ2srt CqYeN/RLzfpdg34emWugqgoVYYuM1R89wMysHaz+If+Gvj4l8KGdENpRi8lyJWLa QSLs7OTi7jAeQj+YsrT5y9WYB4etsUip8XeEH5hNBGJEDVT0OmnSKLkxHqXhXvNx VYETf3E0zoCBQ/jClh3uLqGXNm9UItGl0PNR0cew4dgWtIfDGtO098Wf77WLM1R4 S8bJ7sWwAFJOqMSdye7Ac5S/1J2SyHW0C/ssKaz3cxBIuWatTo8MKnBn0fRPMmvi WjuEcyECggEATIYFJ051HH65A3xJ3I4jyG2sfwdLE7askm0ckqxvA1aq86z5/sve vF1LpisRvtUrPOX6OkJRB8WgtCKQ6qomZ0fs+vLzIsCO858/umU0sbUQ9pRDkHuK XTNsCzWl48bp5lAdcc3Yza0LSNopDtrK6DWfMEFcsP+T3SURLcq9BLtd2yTfEp9r UU02zZ31TnVh5LyuVH3WdaeKUZwqcnZio4BDLtUXidXS6f+V64U67UbO01VOVw0g GYb9JGDKPgRJTFN8VEO5/hKQpPcBXRrFREGGwTafepIkHLvrI671n8AtQXNvv7OM OCDh2Ni1X5DeZ3FrJYQpBzQM7JPVJKWOgwKCAQATd3cKqQCFgrenqbdpj6Xyrj6/ YgGt3DmsVRkBiyXrIXTJw1nsWhTCnQMx0pV904zeR7jObkLpHK0TaZKHglhwBRpI E4m94BSdmeTqnzDOsVGHxGlbU2FbSJQHwMNGzoK2G9XVzmQ3cqtilgEIRzwoE9tS WBcNdtFFGSfCYeTYhOnDCgRawldGq1UQ5uzJU8Juvm3Vdtl6XttKlRJuRLaiEdlg LliW/lhyYfeQWe/Zl8h0HPdoJUMWrWBenEQzWQWVj23REx5D6s6HnZFCf3UliRDo /aSn0j6nfheIya3grmO1EPEeBuCw5BX4pLx8MqZFVjir3/8GbD1gm4z1uhqk -----END RSA PRIVATE KEY----- form-data-4.0.1/test/fixture/unicycle.jpg000066400000000000000000000465361470164731200203730ustar00rootroot00000000000000JFIFHH(ICC_PROFILEappl scnrRGB XYZ acspAPPLappl-appl rXYZgXYZbXYZ0wtptDchadX,rTRCgTRCbTRCdesc=cprtAdscmXYZ tK>XYZ Zs&XYZ (W3XYZ Rsf32 B&lcurv3descCamera RGB ProfileCamera RGB Profilemluc enUS$esES,LdaDK4deDE,fiFI(frFU<itIT,rnlNL$noNO xptBR(JsvSE*jaJPkoKR2zhTW2zhCNKameran RGB-profiiliRGB-profil fr Kamera000 RGB 000000exOMvj_ RGB r_icϏPerfil RGB para CmaraRGB-kameraprofilRGB-Profil fr Kamerasvg: RGB cϏeNRGB-beskrivelse til KameraRGB-profiel CameratT| RGB \ |Perfil RGB de CmeraProfilo RGB FotocameraCamera RGB ProfileProfil RVB de l appareil-phototextCopyright 2003 Apple Computer Inc., all rights reserved.ExifMM* z(12iCASIO COMPUTER CO.,LTD QV-R41 HH1.00 2005:06:21 01:44:12&"0221.BV ^f  n0100v'  2005:06:21 01:44:122005:06:21 01:44:12wC     C  " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?4J;k2;qggyzPnaoTzU1He8aqZx\ sH.֦:Ÿr)iA ڝRN<+cE|~*W&UGK8 Oaq%[[Q\MΙrq>H= \t@Zgj>VfT}@6m#RҮIE{ q4D2+'ƪ}-|c=empG>߅~-W TMSX~= Լ-;Ơ>{ L['eSЍЭd`sz,x1nGFWF)# _ĭK¹cxn~e3Z3#] ֮:sR* `QךOϳ[NF<k|CIERw(`OC]GϋVJ]SsX|0YJ9C",UAQRVhᱰs׿^-f=>Tܴ.>s\أ@ڐ%d!cSө\^ x׽d&r^`xV?v6]lc'xέT9P͌6xY<%YX1TU85mw_%te<}4= Xn>XkM{v7 sm5kɵV_$&H2ϵt 5Ñm+u&H$1N o4{%k n,8Vr:phc<%doZdrx|>˞P}-#9 e@+T:u퟈4X0$]D)Ł\'~c6 ??o8+"8ngѡ3YIgrڥFo@$zrZCĤ (u78ҶbojjuؠlmyesHutخOO3]x<LNjfUk*{+Qԉzkî~"iSэnGd-W+/%VƷqs$mSaz/"ikQULCk2 =܁ξy?-tx%༚w8'eh؎Y KxM,-ȟqcױOU]7Z[ VݝC 9$W4t-'ϕ 'vr@<`׍*nNZTD-ޣld@d]]#&S td$eH^SPY a̅fܤc+dɢ\dmsxVJ#)Ez6|2(ez7T ?9cK!WϫǧZG֦)sYys9qIj4F_ #|[۟NXb/i a`u(|2Njy7зpzmH80Z֗7-WSzh"Iyn!|CȯEPVCw eΏOQCsvψVmm>TRGsծThv"-Ju5o=tRyC꧷ӥz?ÏNy\@0pN/p~t j^Z3s(?)T1mV(I$yqc 9;x\DTU#>|ygN;db7ұ- Ǫ,+Ef H^-)ӵ+8 i6zMEea4; eJ m~|C9E'}O|/YVmӢ'nW n?g/xnhx^oaeI( lqW3׵Cykc4;@^q|TZ=Ob%tޭ B"tEi2nc ~"k$7OȇBZ2n<x ax6~_[<ߥ׏)9:_׿-%ZRךv:.hR# )-"I֍ky.v[>VJ)$D}3#Vs俏>!5]ZXIbϖ=$xZz<6:3,eBȅK>R_"e,hLs!s޽ÒNInq 꽖5mNo34+a PS'tO|o6a sœ+ҽ cOEYx*K-`6k)#^kukTΔő; Oְ[|-upTVΏi{j֗Aw m rbR$r:r[-d}0|#Ծ>5[4JH, `y;^٫Ǟ4oᘖyM!\A?/x_V<+ Fӡq(O|jN*TNVkxE}*i1Q"kC5͞,[Gw!l$y+JDm bmG$t+{ T)qhđH6yjU'$r|UHsׇ:Jǚךͤp[[Z_n%[2an~^ska(R^[X2/;]/., ЪjTNm  [*+˵ k6ޑt0ܪsBT3קT>flCtytuدdeky#;Xҥ]RQ]2yxZ44"mBnϜ4@pO}9KOxMa{-2lHdĕsNr c_٧x襯b?^'SQ>"uX5F,d(x[[>PkH *ez;;0oD9+ J:x?5fG㧁9: I^W%|nO¡_2=Bp)O{5?w6%T:lA R Z#-{V\o2Ism?"hY?#R0}MG+&Qmtm?j̴b~7،yFc?wҴIǡWBz|ՕeOT~h.oNJ>$6Ye5E#lnَԂ=|ӼIk}sF`a` a+FH2:J*c;wX3nZznxNo,-W"4AQE ϠS^ Kwg ˹m,ԳUgzZ.mwdld-/q܊쯾g s j*pH#gxY)|ጣr..#1 eqBq;rvq'ԏǚK񯌬t>/j̑ȋiurȥ* _ 藰E 6/&I30|X&LMK[{>2މ9)xwfĤ h3mz@+2 sWK'+t2n bP+|Y=GP.!!r}[>WȠH;H :okقlX ?CW-< ,TϽ}[q1lMO‰A+azxG)|LG+ H1=3ׁ!Q~$Ixa!qo$|F?\G_? ?|LOoG&x_L_/-$F0d8?;!D>ث!';u <ȶ&J?_ <5({Cƫ*{q??@hZu>gc#5 }58fRc y4۟r4K| ɒ9+tUWZ%q!x*OvŪNJ5q= /ua3 i~Qm$de }*R@{U[h=<9cm-Hd$U'gqL$ž6a'}J* ¯ qISgEa ~{Vމkeqszम34ͻ{ܓ~]$|e/y֧/ ǧ2+5l/'9o|e[Kn,toY{u>2 kddy6耪+l/^ҿh C/h0iv! }r1$.}0~ҵ3sLڗlZDRebL2:c= fTG=ji~cXto$.ّ_'i\V煮>8N%܎]Ā3Th_7Unm\n/.M>lW/~jwa'[ +tZG- ZG lH$Wº<:Z<&(b y#͟ \.Zu)$poz?6Y~'-.FKYˍ)P9 _7~(i{~'!ѼIM-V) mrݫ3VJmgpݟֱ\ &T<8ledYVdzqvƩ;iO yCͳG"ܴD#WϪjZMbU\KpӹiWtp8=+ښ]Ou ;g<"ĉ֔^)sM8u:)B[ |Z?rB r8֨rP}:zV5DL  F;匑R_a4}?ɣGS8nLTb&Q6cig>ߟYv>3,B78ZǨ6Q+CjmawSzv4i:$q^{Ū<+fWhl>yo%UI0@=xаMˣ.vt>[K(͟<($yѥٱa}kb,Y|X&Kr7sW "Fk;FHU(#uNꖅZb. Rk̯r۩.I(~xš}m!4@:漷ƛtK4Okfoa0/XHgƽ6fM!qu{V|ijqy: 85ۈqG5:?`.ol[꺝%؈"7^'Oعͣ^Gd,\o_$O=Rbm;KkaȀyakY[ړziЮ4DUaVPqGNkJ :oZ+WѯE?Jy! k}Q2|4$SDPݸҫì^iumjDv!Qw >^:)I3fYK 8w:MsR ?Ig&nwB5 =k>:~d%Ƥۏ8*@0s+dU gR{g]SN[mF) w[J`XMK?=?g"~QMB _Rh:n E3^z !bP"27{ҾP7s> Z`y( c5i?~:/ux~Ѧ~DžE2}nFCʫn_\𳪽_GSzC=hnL6VPr1XPx7I5,4Ůyeg vݻ{q-|bŏ*PY*J9G)}?w gr>vnj~^"KK#|ij)E;)ag ;7Z>.iv&wqD'ˌ1+̓]SM[IWҢSJg <E [l6`Ue3ǵs|}2 hA;d\m`qWGv^5ھ/`nMEb6qY}_kF(,vlp@kkZf,Y9ݹOsYW:]F,HN;H8 E{t6Puf{_Kg[nɠPydž}xo ޿&xc5K;iZ 36 3хM29ibpJ>74}B{<{l(Ưx+[fF\gnt8?VnNwuԊ4K%gh;lĞy$fƳӁY؁@@׫9ګ"*gs-O#!>⻿xv\F Pcd*ٓIŨ۷@A+_cӖ2wm\fƤUGPn)G'mkֺߊ5B7@mоv-կGK u@ݹoA2nT1\m_,%$ͳ|zחQsٹdфcSwC3674+KS{Jxw_©OZv} ԙ疩4Y4//EsOB0 ڹvkXK} 7nY~R_Q/_V΃%&j mܬ)<8qlfp۔b${"[7LIr)<P #בF2sV=Җ]]M_gLdybsGJijj7rZɴ& *Xq2VUN1,pFx9YuԺg9㸕[ ;=zW9J:m+=Zv(jTw44Eir[M$=_ kϭ^ۨK60PNG>fzk~kܮWogw>$i%M݌Q@fܸ6Yt=\3Q%yJ-G[kWasjkm+ȯdP?{vھoym]˅bj6|52mM0vCՎ;q^}~{ i bku!EoЌ!*OԮ$]b-g{g|Y޷wPmxv;{ZM kKZvuϥbx GR8 "8a2pk223ھ^j o/Aܒ.AU6173YpۿWY"nz5VK!f囖WGR՞ νNXW>qs_lKHZ98>%m[Դ+{U'-frLyU⾐)"RR8#:l5Euښ0CGehYg^ b¾ ӛ.l#/[`w/#r+ԗ~V}Ԓ;;k 4m-lrX%9*x!{՚Li\cy5v}Gk |*|cou{._·Hm,F`*& ʉG^e 9Oe/q6< 1>?u ƺ9SK4+|qU{R|?p\*"ZE!{ߵtFsS_Ye-#NP|ɲ*˱KJ$zhc+y~#NIBQI{m4nu5cH#l-ʑ(;Jm?Z<5j#!MOA%%K"g+q :+Ɓ-;S1\ ӧ.5g\6# PѤh98!+zM;>O[ N?GkDû`#E~ixQ~(}$Iovƀ|aԚ ;C=ИY"rd%'3$#bOP__3Qc}I֧V>ዻK b=8=2 d ^o[Ȃ8!Ms&[ea<盖-`jgs>dO9g}kjW=FL<Ui5M]ݴ=.$ZvwR{mlax{e:\fҤExrnjq_GO7v3έͯ+o#RɄ)nIoq.c'MgyK[Hӓ_wK' 52b;mG(CJ[;Hb J0xX-q0UcV6rL򿃾 .<[k3\[k%FW5LT4?b刖")GOr\ww&8"xJK-6Vr+` `w9?gMX\OmiqtĴsl]G8ǽt>3x'/ص G)ϺD} tӓo/絗Qͼ, ' j|DʼZ5%mV%/G2]Ќuw]sgs33 " %c ذn.~PէXg–sݐe1\~F|7:z&]DhYK K(K+*כ :I?XVcR>T)>fڽoE}z/cq[]2Vkxs2xEҵkVּζ[<YA&/AҮ>C])NK4#qctnc5ͦEr<-^ q!3} fuƔi>Xϳ|󺕥UJڏnk?a}{=mI3BUF@ppA'َJ֣V5l6ӑnXgWֽՆ二J ͵#ǻnXF̎(릿_AMgz[լzf@_FX)y8 4Zohx;~ۑc[h1)bnܪ@\s%;V Dl1<ܬG͌ϭ};[xb]G>K NU#]\_-X}{?Zxi6ge$,vHf吖F>5]Yq<2 R;_W_K+llIt8j9î^S&)5%]`״gUL,$dLӟʪxe -,8g޾l]v{- xiRO㡯IU['Q-q͚Ƭ**9<}6,, >[[?'3sb0*wVzWk^ +ĄQhVX^ 7 f̹\1N]lUfqtv^3}+"F鉕=X=`qELR֪9±XZ6vq@u6]隸${EٍڀׯJ_7%ŏtGzqyMmf0ˏxJvK"K;fK KуBz1S0=; P9\Z'miw<leυ~-5\ǧ&A<>#39O5QkEvp2GZ)aq}g]KKb5TӤLwOp$LU%NV+^ќ 6׳ [4*rwzv4gi7o+iں)rnch@'y40U}~}kroo9t [Ygv@0hI`N5\#QS[8Ճ2pS|VhTN3WwO!~45+ }vt}BǷz Wֱ\I5q:;=|i*aSGn^TIu[[̇KosXZXy$; ̬:OBj 8qҼtxmv?  %z`i]y3> eQ-V6tTkΚp+Ru#zsmȇ$)ԱK8guFGӊ4k%\۴( N ([HkdIp{utԞ |)TqM+~'ul < 66Zb)1/֠}$'tiqțpۑnUS~)nŨB =Zqc+#=:(tH m9?HmCy8O&<Yyt&xq' |?59'k?)U5gĨxW83_Q O޼)]y/oSkZ(%OaC{/2i+Ws>N1_xbz>k~3"09r5ZKW_N^FI46.%r;_sKfhMcԦap=\_ h^,wV2n}s޾ү!ִK'QIG,6S] @۵%y{WK1u0 C_Jm-֠zx:όn$i- FTG!A~xnu)bB>{#Mg᷋|e5޵;{5Ҡ ARz?SS,g{q1#B,7Smߐf1T+%Ӣ>/95rk¢[jՆȮ.m_'?Eo}M-٤2*nvcS^7Oђ=.L`t^f]J.e90`[[?0okwG=1*pߕmj:hܷkBOUeC~+8=HG3m]0(?luZiy3FO'|ys+{KMFħMEvp@{W5wr-) ~f>13_hj_@&[X:O(Kpm3)wMbUU;T[ZRI ]>Mg_H$e#wS׆Zu[;m#T ႗_UyᾒZ Fa2yM[x:oBѡ60Lν%wMz=S_qɌ˽fɢGO&kgwmh^*ljQYCjQ[:hm zZ+|C:-9ui蠞V9>ʓtz439N3nIYM|<3VjzMUk7Oi xHԺucUL>!Qv&{-m)&ɐ?Xj1 ׅ@0V &s6`~_@w⹏_Z⾑ <0*ַ#8I'٧ ʬ8kתkdG^쭶wUDe<-jH b>9V_6z_X}ľ  }j@ ,eE Nsx<+sL$^t2XKʽ~PznC?{$^߳ǁ:,v0<[2qp1I|H/Kڬ bhWn3͚=Շuilt/oBڄ2pr_hPRZ3}:=zױjrP}7A$NG|+u6f3$L.z֥\4_H49!Ip H-ƿٶ7P ڇͺꚘ#OU~ڟTiϞ>uxwAc=C #)m yqМr鋨&WzmιeCvX2D~5PSOkpOp.nLt9{|form-data-4.0.1/test/fixture/unknown_file_type000066400000000000000000000000001470164731200215100ustar00rootroot00000000000000form-data-4.0.1/test/fixture/veggies.txt000066400000000000000000000000251470164731200202270ustar00rootroot00000000000000Veggies are healthy. form-data-4.0.1/test/integration/000077500000000000000000000000001470164731200166755ustar00rootroot00000000000000form-data-4.0.1/test/integration/test-custom-content-type.js000066400000000000000000000050441470164731200241540ustar00rootroot00000000000000var common = require('../common'); var assert = common.assert; var http = require('http'); var mime = require('mime-types'); var fs = require('fs'); var FormData = require(common.dir.lib + '/form_data'); // wrap non simple values into function // just to deal with ReadStream "autostart" var FIELDS = { 'no_type': { value: 'my_value' }, 'custom_type': { value: 'my_value', expectedType: 'image/png', options: { contentType: 'image/png' } }, 'default_type': { expectedType: FormData.DEFAULT_CONTENT_TYPE, value: common.defaultTypeValue }, 'implicit_type': { expectedType: mime.lookup(common.dir.fixture + '/unicycle.jpg'), value: function() { return fs.createReadStream(common.dir.fixture + '/unicycle.jpg'); } }, 'overridden_type': { expectedType: 'image/png', options: { contentType: 'image/png' }, value: function() { return fs.createReadStream(common.dir.fixture + '/unicycle.jpg'); } } }; var fieldsPassed = false; var server = http.createServer(function(req, res) { var body = ''; var boundry = req.headers['content-type'].split('boundary=').pop(); req.on('data', function (data) { body += data.toString('utf-8'); }); req.on('end', function () { // Separate body into individual files/fields and remove leading and trailing content. var fields = body.split(boundry).slice(1, -1); var fieldNames = Object.keys(FIELDS); assert.ok(fields.length === fieldNames.length); for (var i = 0; i < fieldNames.length; i++) { assert.ok(fields[i].indexOf('name="' + fieldNames[i] + '"') > -1); if (!FIELDS[fieldNames[i]].expectedType) { assert.equal(fields[i].indexOf('Content-Type'), -1, 'Expecting ' + fieldNames[i] + ' not to have Content-Type'); } else { assert.ok(fields[i].indexOf('Content-Type: ' + FIELDS[fieldNames[i]].expectedType) > -1, 'Expecting ' + fieldNames[i] + ' to have Content-Type ' + FIELDS[fieldNames[i]].expectedType); } } fieldsPassed = true; res.end(); }); }); server.listen(common.port, function() { var form = new FormData(); var field; for (var name in FIELDS) { if (!FIELDS.hasOwnProperty(name)) { continue; } field = FIELDS[name]; // important to append ReadStreams within the same tick if ((typeof field.value == 'function')) { field.value = field.value(); } form.append(name, field.value, field.options); } // custom params object passed to submit common.actions.submit(form, server); }); process.on('exit', function() { assert.ok(fieldsPassed); }); form-data-4.0.1/test/integration/test-custom-filename.js000066400000000000000000000075051470164731200233070ustar00rootroot00000000000000/* test custom filename and content-type: re: https://github.com/felixge/node-form-data/issues/29 */ var common = require('../common'); var assert = common.assert; var mime = require('mime-types'); var http = require('http'); var fs = require('fs'); var path = require('path'); var FormData = require(common.dir.lib + '/form_data'); var IncomingForm = require('formidable').IncomingForm; var knownFile = path.join(common.dir.fixture, 'unicycle.jpg'); var unknownFile = path.join(common.dir.fixture, 'unknown_file_type'); var relativeFile = path.relative(path.join(knownFile, '..', '..'), knownFile); var options = { filename: 'test.png', contentType: 'image/gif' }; var server = http.createServer(function(req, res) { var form = new IncomingForm({uploadDir: common.dir.tmp}); form.parse(req, function (err, fields, files) { assert(!err); assert('custom_everything' in files); assert.strictEqual(files['custom_everything'].name, options.filename, 'Expects custom filename'); assert.strictEqual(files['custom_everything'].type, options.contentType, 'Expects custom content-type'); assert('custom_filename' in files); assert.strictEqual(files['custom_filename'].name, options.filename, 'Expects custom filename'); assert.strictEqual(files['custom_filename'].type, mime.lookup(knownFile), 'Expects original content-type'); assert('custom_filepath' in files); assert.strictEqual(files['custom_filepath'].name, relativeFile.replace(/\\/g, '/'), 'Expects custom filepath'); assert.strictEqual(files['custom_filepath'].type, mime.lookup(knownFile), 'Expects original content-type'); assert('unknown_with_filename' in files); assert.strictEqual(files['unknown_with_filename'].name, options.filename, 'Expects custom filename'); assert.strictEqual(files['unknown_with_filename'].type, mime.lookup(options.filename), 'Expects filename-derived content-type'); assert('unknown_with_filename_as_object' in files); assert.strictEqual(files['unknown_with_filename_as_object'].name, options.filename, 'Expects custom filename'); assert.strictEqual(files['unknown_with_filename_as_object'].type, mime.lookup(options.filename), 'Expects filename-derived content-type'); assert('unknown_with_name_prop' in files); assert.strictEqual(files['unknown_with_name_prop'].name, options.filename, 'Expects custom filename'); assert.strictEqual(files['unknown_with_name_prop'].type, mime.lookup(options.filename), 'Expects filename-derived content-type'); assert('unknown_everything' in files); assert.strictEqual(files['unknown_everything'].type, FormData.DEFAULT_CONTENT_TYPE, 'Expects default content-type'); res.writeHead(200); res.end('done'); }); }); server.listen(common.port, function() { var form = new FormData(); // Explicit contentType and filename. form.append('custom_everything', fs.createReadStream(knownFile), options); // Filename only with real file form.append('custom_filename', fs.createReadStream(knownFile), options.filename); // Filename only with unknown file form.append('unknown_with_filename', fs.createReadStream(unknownFile), options.filename); // Filename only with unknown file form.append('unknown_with_filename_as_object', fs.createReadStream(unknownFile), {filename: options.filename}); // Filename with relative path form.append('custom_filepath', fs.createReadStream(knownFile), {filepath: relativeFile}); // No options or implicit file type from extension on name property. var customNameStream = fs.createReadStream(unknownFile); customNameStream.name = options.filename; form.append('unknown_with_name_prop', customNameStream); // No options or implicit file type from extension. form.append('unknown_everything', fs.createReadStream(unknownFile)); common.actions.submit(form, server); }); form-data-4.0.1/test/integration/test-custom-headers-object.js000066400000000000000000000023131470164731200243760ustar00rootroot00000000000000/* test custom headers object. https://github.com/form-data/form-data/issues/133 */ var common = require('../common'); var assert = common.assert; var http = require('http'); var FormData = require(common.dir.lib + '/form_data'); var testHeader = { 'X-Test-Fake': 123 }; var expectedLength; var server = http.createServer(function(req, res) { assert.ok( typeof req.headers['content-length'] !== 'undefined' ); assert.equal(req.headers['content-length'], expectedLength); req.on('data', function (data) { assert.equal( data.toString('utf8').split('\n')[3], 'X-Test-Fake: 123\r' ); }); res.writeHead(200); res.end('done'); }); server.listen(common.port, function() { var form = new FormData(); var options = { header: testHeader, // override content-length, // much lower than actual buffer size (1000) knownLength: 1 }; var bufferData = []; for (var z = 0; z < 1000; z++) { bufferData.push(1); } var buffer = new Buffer(bufferData); form.append('my_buffer', buffer, options); // (available to req handler) expectedLength = form._lastBoundary().length + form._overheadLength + options.knownLength; common.actions.submit(form, server); }); form-data-4.0.1/test/integration/test-custom-headers-string.js000066400000000000000000000024651470164731200244460ustar00rootroot00000000000000/* test custom headers, added in pull request: https://github.com/felixge/node-form-data/pull/17 */ var common = require('../common'); var assert = common.assert; var http = require('http'); var FormData = require(common.dir.lib + '/form_data'); var CRLF = '\r\n'; var testHeader = 'X-Test-Fake: 123'; var expectedLength; var server = http.createServer(function(req, res) { assert.ok( typeof req.headers['content-length'] !== 'undefined' ); assert.equal(req.headers['content-length'], expectedLength); req.on('data', function (data) { assert.equal( data.toString('utf8').split('\n')[2], 'X-Test-Fake: 123\r' ); }); res.writeHead(200); res.end('done'); }); server.listen(common.port, function() { var form = new FormData(); var options = { header: CRLF + '--' + form.getBoundary() + CRLF + testHeader + CRLF + CRLF, // override content-length, // much lower than actual buffer size (1000) knownLength: 1 }; var bufferData = []; for (var z = 0; z < 1000; z++) { bufferData.push(1); } var buffer = new Buffer(bufferData); form.append('my_buffer', buffer, options); // (available to req handler) expectedLength = form._lastBoundary().length + form._overheadLength + options.knownLength; common.actions.submit(form, server); }); form-data-4.0.1/test/integration/test-errors.js000066400000000000000000000043501470164731200215260ustar00rootroot00000000000000var common = require('../common'); var assert = common.assert; var FormData = require(common.dir.lib + '/form_data'); var fake = require('fake').create(); var path = require('path'); var fs = require('fs'); var http = require('http'); // https://github.com/felixge/node-form-data/issues/38 (function testAppendArray() { var form = new FormData(); var callback = fake.callback('testAppendArray-onError-append'); fake.expectAnytime(callback, ['Arrays are not supported.']); form.on('error', function(err) { // workaround for expectAnytime handling objects callback(err.message); }); form.append('my_array', ['bird', 'cute']); })(); (function testGetLengthSync() { var fields = [ { name: 'my_string', value: 'Test 123' }, { name: 'my_image', value: fs.createReadStream(common.dir.fixture + '/unicycle.jpg') } ]; var form = new FormData(); var expectedLength = 0; fields.forEach(function(field) { form.append(field.name, field.value); if (field.value.path) { var stat = fs.statSync(field.value.path); expectedLength += stat.size; } else { expectedLength += field.value.length; } }); expectedLength += form._overheadLength + form._lastBoundary().length; var callback = fake.callback('testGetLengthSync-onError-getLengthSync'); fake.expectAnytime(callback, ['Cannot calculate proper length in synchronous way.']); form.on('error', function(err) { // workaroud for expectAnytime handling objects callback(err.message); }); var calculatedLength = form.getLengthSync(); // getLengthSync DOESN'T calculate streams length assert.ok(expectedLength > calculatedLength); })(); (function testStreamError() { var req; var form = new FormData(); // make it windows friendly var fakePath = path.resolve('/why/u/no/exists'); var src = fs.createReadStream(fakePath); var server = http.createServer(); var addr = 'http://localhost:' + common.port; form.append('fake-stream', src); form.on('error', function(err) { assert.equal(err.code, 'ENOENT'); assert.equal(err.path, fakePath); req.on('error', function() {}); server.close(); }); server.listen(common.port, function() { req = form.submit(addr); }); })(); form-data-4.0.1/test/integration/test-form-get-length-sync.js000066400000000000000000000046141470164731200241660ustar00rootroot00000000000000var common = require('../common'); var assert = common.assert; var FormData = require(common.dir.lib + '/form_data'); var fs = require('fs'); var Readable = require('stream').Readable; (function testGetLengthSync() { var fields = [ { name: 'my_number', value: 123 }, { name: 'my_string', value: 'Test 123' }, { name: 'my_buffer', value: new Buffer('123') } ]; var form = new FormData(); var expectedLength = 0; fields.forEach(function(field) { form.append(field.name, field.value); expectedLength += ('' + field.value).length; }); expectedLength += form._overheadLength + form._lastBoundary().length; var calculatedLength = form.getLengthSync(); assert.equal(expectedLength, calculatedLength); })(); (function testGetLengthSyncWithKnownLength() { var fields = [ { name: 'my_number', value: 123 }, { name: 'my_string', value: 'Test 123' }, { name: 'my_buffer', value: new Buffer('123') }, { name: 'my_image', value: fs.createReadStream(common.dir.fixture + '/unicycle.jpg'), options: { knownLength: fs.statSync(common.dir.fixture + '/unicycle.jpg').size } } ]; var form = new FormData(); var expectedLength = 0; fields.forEach(function(field) { form.append(field.name, field.value, field.options); if (field.value.path) { var stat = fs.statSync(field.value.path); expectedLength += stat.size; } else { expectedLength += ('' + field.value).length; } }); expectedLength += form._overheadLength + form._lastBoundary().length; var calculatedLength = form.getLengthSync(); assert.equal(expectedLength, calculatedLength); })(); (function testReadableStreamData() { var form = new FormData(); var util = require('util'); util.inherits(CustomReadable, Readable); /** * Custion readable constructor * @param {Object} opt options * @constructor */ function CustomReadable(opt) { Readable.call(this, opt); this._max = 2; this._index = 1; } CustomReadable.prototype._read = function() { var i = this._index++; if (i > this._max) { this.push(null); } else { this.push('' + i); } }; form.append('my_txt', new CustomReadable()); assert.throws(function() { form.getLengthSync(); }, /Cannot calculate proper length in synchronous way/); })(); form-data-4.0.1/test/integration/test-form-get-length.js000066400000000000000000000062331470164731200232130ustar00rootroot00000000000000var common = require('../common'); var assert = common.assert; var FormData = require(common.dir.lib + '/form_data'); var fake = require('fake').create(); var fs = require('fs'); var Readable = require('stream').Readable; (function testEmptyForm() { var form = new FormData(); var callback = fake.callback('testEmptyForm-getLength'); var calls = fake.expectAnytime(callback, [null, 0]).calls; form.getLength(callback); // Make sure our response is async assert.strictEqual(calls.length, 0); })(); (function testUtf8String() { var FIELD = 'my_field'; var VALUE = 'May the € be with you'; var form = new FormData(); form.append(FIELD, VALUE); var callback = fake.callback('testUtf8String-getLength'); var expectedLength = form._overheadLength + Buffer.byteLength(VALUE) + form._lastBoundary().length; fake.expectAnytime(callback, [null, expectedLength]); form.getLength(callback); })(); (function testBuffer() { var FIELD = 'my_field'; var VALUE = new Buffer(23); var form = new FormData(); form.append(FIELD, VALUE); var callback = fake.callback('testBuffer-getLength'); var expectedLength = form._overheadLength + VALUE.length + form._lastBoundary().length; fake.expectAnytime(callback, [null, expectedLength]); form.getLength(callback); })(); (function testStringFileBufferFile() { var fields = [ { name: 'my_field', value: 'Test 123' }, { name: 'my_image', value: fs.createReadStream(common.dir.fixture + '/unicycle.jpg') }, { name: 'my_buffer', value: new Buffer('123') }, { name: 'my_txt', value: fs.createReadStream(common.dir.fixture + '/veggies.txt') } ]; var form = new FormData(); var expectedLength = 0; fields.forEach(function(field) { form.append(field.name, field.value); if (field.value.path) { var stat = fs.statSync(field.value.path); expectedLength += stat.size; } else { expectedLength += field.value.length; } }); expectedLength += form._overheadLength + form._lastBoundary().length; var callback = fake.callback('testStringFileBufferFile-getLength'); fake.expectAnytime(callback, [null, expectedLength]); form.getLength(callback); })(); (function testReadableStreamData() { var form = new FormData(); // var expectedLength = 0; var util = require('util'); util.inherits(CustomReadable, Readable); /** * Custion readable constructor * @param {Object} opt options * @constructor */ function CustomReadable(opt) { Readable.call(this, opt); this._max = 2; this._index = 1; } CustomReadable.prototype._read = function() { var i = this._index++; if (i > this._max) { this.push(null); } else { this.push('' + i); } }; form.append('my_txt', new CustomReadable()); // expectedLength += form._overheadLength + form._lastBoundary().length; // there is no way to determine the length of this readable stream. var callback = fake.callback(arguments.callee.name + '-getLength'); fake.expectAnytime(callback, ['Unknown stream', undefined]); form.getLength(function(err, len) { callback(err,len); }); })(); form-data-4.0.1/test/integration/test-get-boundary.js000066400000000000000000000007411470164731200226120ustar00rootroot00000000000000var common = require('../common'); var assert = common.assert; var FormData = require(common.dir.lib + '/form_data'); (function testOneBoundaryPerForm() { var form = new FormData(); var boundary = form.getBoundary(); assert.equal(boundary, form.getBoundary()); assert.equal(boundary.length, 50); })(); (function testUniqueBoundaryPerForm() { var formA = new FormData(); var formB = new FormData(); assert.notEqual(formA.getBoundary(), formB.getBoundary()); })(); form-data-4.0.1/test/integration/test-get-buffer.js000066400000000000000000000035451470164731200222450ustar00rootroot00000000000000var common = require('../common'); var assert = common.assert; var FormData = require(common.dir.lib + '/form_data'); (function testTypeIsBuffer() { var form = new FormData(); form.append( 'String', 'Some random string' ); var buffer = form.getBuffer(); assert.equal(typeof buffer === 'object' && Buffer.isBuffer(buffer), true); })(); (function testBufferIsValid() { var form = new FormData(); var stringName = 'String'; var stringValue = 'This is a random string'; var intName = 'Int'; var intValue = 1549873167987; var bufferName = 'Buffer'; var bufferValue = Buffer.from([0x00,0x4a,0x45,0x46,0x46,0x52,0x45,0x59,0x255]); // Fill the formData object form.append( stringName, stringValue ); form.append( intName, intValue ); form.append( bufferName, bufferValue ); // Get the resulting Buffer var buffer = form.getBuffer(); // Generate expected code. var boundary = form.getBoundary(); var expected = Buffer.concat( [ Buffer.from( '--' + boundary + FormData.LINE_BREAK + 'Content-Disposition: form-data; name="' + stringName + '"' + FormData.LINE_BREAK + FormData.LINE_BREAK + stringValue + FormData.LINE_BREAK + '--' + boundary + FormData.LINE_BREAK + 'Content-Disposition: form-data; name="' + intName + '"' + FormData.LINE_BREAK + FormData.LINE_BREAK + intValue + FormData.LINE_BREAK + '--' + boundary + FormData.LINE_BREAK + 'Content-Disposition: form-data; name="' + bufferName + '"' + FormData.LINE_BREAK + 'Content-Type: application/octet-stream' + FormData.LINE_BREAK + FormData.LINE_BREAK), bufferValue, Buffer.from( FormData.LINE_BREAK + '--' + boundary + '--' + FormData.LINE_BREAK ) ] ); // Test if the buffer content, equals the expected buffer. assert.equal(buffer.length, expected.length); assert.equal(buffer.toString('hex'), expected.toString('hex')); })(); form-data-4.0.1/test/integration/test-http-response.js000066400000000000000000000024071470164731200230260ustar00rootroot00000000000000var common = require('../common'); var assert = common.assert; var http = require('http'); var parseUrl = require('url').parse; var FormData = require(common.dir.lib + '/form_data'); // static server prepared for all tests var remoteFile = 'http://localhost:' + common.staticPort + '/unicycle.jpg'; var server; var parsedUrl = parseUrl(remoteFile); var options = { method: 'get', port: parsedUrl.port || 80, path: parsedUrl.pathname, host: parsedUrl.hostname }; var FIELDS = { 'my_field': { value: 'my_value' }, 'my_buffer': { type: FormData.DEFAULT_CONTENT_TYPE, value: common.defaultTypeValue }, 'remote_file': { value: 'TBD', name: remoteFile } }; // request static file http.request(options, function(response) { var form = new FormData(); // add http response to the form fields FIELDS['remote_file'].value = response; common.actions.populateFields(form, FIELDS); server.listen(common.port, function() { common.actions.submit(form, server); }); }).end(); // count total var fieldsPassed = Object.keys(FIELDS).length; // prepare form-receiving http server server = common.testFields(FIELDS, function(fields){ fieldsPassed = fields; }); process.on('exit', function() { assert.strictEqual(fieldsPassed, 0); }); form-data-4.0.1/test/integration/test-last_boundary-line_break.js000066400000000000000000000015211470164731200251460ustar00rootroot00000000000000var http = require('http'); var common = require('../common'); var assert = common.assert; var FormData = require(common.dir.lib + '/form_data'); var server; /** * Test submission of proper line ending */ function submitForm() { var form = new FormData(); form.append('field', 'value'); common.actions.submit(form, server); } // create https server server = http.createServer(function(req, res) { var body = ''; req.setEncoding('utf8'); // old and simple req.on('data', function(data) { body += data; }); req.on('end', function() { // last character(s) sequence equals predefined line break assert.strictEqual(body.substr(-1 * FormData.LINE_BREAK.length), FormData.LINE_BREAK); res.writeHead(200); res.end(); }); }); // when https server ready submit form server.listen(common.port, submitForm); form-data-4.0.1/test/integration/test-options-override.js000066400000000000000000000003511470164731200235170ustar00rootroot00000000000000var common = require('../common'); var assert = common.assert; var FormData = require(common.dir.lib + '/form_data'); var form = new FormData({maxDataSize: 20 * 1024 * 1024}); assert.strictEqual(form.maxDataSize, 20 * 1024 * 1024); form-data-4.0.1/test/integration/test-pipe.js000066400000000000000000000040121470164731200211420ustar00rootroot00000000000000var common = require('../common'); var assert = common.assert; var http = require('http'); var mime = require('mime-types'); var request = require('request'); var fs = require('fs'); var FormData = require(common.dir.lib + '/form_data'); var IncomingForm = require('formidable').IncomingForm; var remoteFile = 'http://localhost:' + common.staticPort + '/unicycle.jpg'; // wrap non simple values into function // just to deal with ReadStream "autostart" var FIELDS = { 'my_field': { value: 'my_value' }, 'my_buffer': { type: FormData.DEFAULT_CONTENT_TYPE, value: common.defaultTypeValue }, 'my_file': { type: mime.lookup(common.dir.fixture + '/unicycle.jpg'), value: function() { return fs.createReadStream(common.dir.fixture + '/unicycle.jpg'); } }, 'remote_file': { type: mime.lookup(common.dir.fixture + '/unicycle.jpg'), value: function() { return request(remoteFile); } } }; var fieldsPassed = Object.keys(FIELDS).length; var server = http.createServer(function(req, res) { var form = new IncomingForm({uploadDir: common.dir.tmp}); form.parse(req); common.actions.checkForm(form, FIELDS, function(fieldsChecked) { // keep track of number of the processed fields fieldsPassed = fieldsPassed - fieldsChecked; // finish it common.actions.formOnEnd(res); }); }); server.listen(common.port, function() { var form = new FormData(); var field; for (var name in FIELDS) { if (!FIELDS.hasOwnProperty(name)) { continue; } field = FIELDS[name]; // important to append ReadStreams within the same tick if ((typeof field.value == 'function')) { field.value = field.value(); } form.append(name, field.value); } var req = http.request({ method: 'post', port: common.port, path: '/upload', headers: form.getHeaders() }); form.pipe(req); req.on('response', function(res) { // unstuck new streams res.resume(); server.close(); }); }); process.on('exit', function() { assert.strictEqual(fieldsPassed, 0); }); form-data-4.0.1/test/integration/test-ranged-filestream.js000066400000000000000000000054001470164731200236000ustar00rootroot00000000000000/* test ranged fs.createReadStream re: https://github.com/felixge/node-form-data/issues/71 */ var common = require('../common'); var assert = common.assert; var http = require('http'); var fs = require('fs'); var FormData = require(common.dir.lib + '/form_data'); var IncomingForm = require('formidable').IncomingForm; var testSubjects = { 'a_file': { file: 'veggies.txt', start: 8, end: 18 }, 'b_file': { file: 'veggies.txt', start: 6 }, 'c_file': { file: 'veggies.txt', end: 16 }, 'd_file': { file: 'veggies.txt', start: 0, end: 16 }, 'e_file': { file: 'veggies.txt', start: 0, end: 0 } }; /** * Accumulates read data size * * @param {string} data - chunk of read data */ function readSizeAccumulator(data) { this.readSize += data.length; } var server = http.createServer(function(req, res) { var requestBodyLength = 0; // calculate actual length of the request body req.on('data', function(data) { requestBodyLength += data.length; }); req.on('end', function() { // make sure total Content-Length is properly calculated assert.equal(req.headers['content-length'], requestBodyLength); // successfully accepted request and it's good res.writeHead(200); }); var form = new IncomingForm({uploadDir: common.dir.tmp}); form.parse(req); form .on('file', function(name, file) { // make sure chunks are the same size assert.equal(file.size, testSubjects[name].readSize); // clean up tested subject delete testSubjects[name]; }) .on('end', function() { // done here res.end(); }); }); server.listen(common.port, function() { var form = new FormData(); var name, options; // add test subjects to the form for (name in testSubjects) { if (!testSubjects.hasOwnProperty(name)) { continue; } options = {encoding: 'utf8'}; if (testSubjects[name].start) { options.start = testSubjects[name].start; } if (testSubjects[name].end) { options.end = testSubjects[name].end; } form.append(name, testSubjects[name].fsStream = fs.createReadStream(common.dir.fixture + '/' + testSubjects[name].file, options)); // calculate data size testSubjects[name].readSize = 0; testSubjects[name].fsStream.on('data', readSizeAccumulator.bind(testSubjects[name])); } form.submit('http://localhost:' + common.port + '/', function(err, res) { if (err) { throw err; } assert.strictEqual(res.statusCode, 200); // wait for server to finish res.on('end', function() { // check that all subjects were tested assert.strictEqual(Object.keys(testSubjects).length, 0); server.close(); }); // unstuck new streams res.resume(); }); }); form-data-4.0.1/test/integration/test-request.js000066400000000000000000000046221470164731200217040ustar00rootroot00000000000000/** * Show & Test for `mikeal/request` library * as bonus shows progress monitor implementation */ var common = require('../common'); var assert = common.assert; var http = require('http'); var path = require('path'); var mime = require('mime-types'); var request = require('request'); var FormData = require(common.dir.lib + '/form_data'); var fs = require('fs'); var IncomingForm = require('formidable').IncomingForm; var fileName = common.dir.fixture + '/unicycle.jpg'; var myFile = function() { return fs.createReadStream(fileName); }; var numItems = 5; // Make request to use our FormData request.prototype.form = function (form) { var self = this; if (form) { if (!/^application\/x-www-form-urlencoded\b/.test(self.getHeader('content-type'))) { self.setHeader('content-type', 'application/x-www-form-urlencoded'); } self.body = (typeof form === 'string') ? self._qs.rfc3986(form.toString('utf8')) : self._qs.stringify(form).toString('utf8'); return self; } // create form-data object self._form = new FormData(); self._form.on('error', function(err) { err.message = 'form-data: ' + err.message; self.emit('error', err); self.abort(); }); return self._form; }; var server = http.createServer(function(req, res) { var form = new IncomingForm({uploadDir: common.dir.tmp}); form.parse(req); form .on('file', function(name, file) { numItems--; assert.strictEqual(file.name, path.basename(fileName)); assert.strictEqual(file.type, mime.lookup(file.name)); }) .on('end', common.actions.formOnEnd.bind(null, res)); }); server.listen(common.port, function() { var uploadSize = 0; var uploaded = 0; var r = request.post('http://localhost:' + common.port + '/', function(err, res) { assert.ifError(err); assert.strictEqual(res.statusCode, 200); server.close(); }); var form = r.form(); for (var i = 0; i < numItems; i++) { form.append('file_' + i, myFile()); } // get upload size form.getLength(function(err, size) { assert.equal(err, null); uploadSize = size; assert.ok(uploadSize > 0); }); // calculate uploaded size chunk by chunk form.on('data', function(data) { uploaded += data.length; }); // done uploading compare sizes form.on('end', function() { assert.equal(uploaded, uploadSize); }); }); process.on('exit', function() { assert.strictEqual(numItems, 0); }); form-data-4.0.1/test/integration/test-return-http-request.js000066400000000000000000000035201470164731200241720ustar00rootroot00000000000000/* test return http request, added for issue #47: https://github.com/felixge/node-form-data/issues/47 Checking correct length header and request object */ var common = require('../common'); var assert = common.assert; var http = require('http'); var FormData = require(common.dir.lib + '/form_data'); var expectedLength; var dataSize = 1000000; var server = http.createServer(function(req, res) { var uploaded = 0; assert.ok( typeof req.headers['content-length'] !== 'undefined' ); assert.equal(req.headers['content-length'], expectedLength); // check for uploaded body req.on('data', function(data) { uploaded += data.length; }); req.on('end', function() { // compare uploaded total to the expected length assert.equal(uploaded, expectedLength); res.writeHead(200); res.end('done'); }); }); server.listen(common.port, function() { var R, oWrite, progress = 0, form = new FormData(); var bufferData = []; for (var z = 0; z < dataSize; z++) { bufferData.push(1); } var buffer = new Buffer(bufferData); form.append('my_buffer', buffer); // (available to req handler) expectedLength = form._lastBoundary().length + form._overheadLength + dataSize; R = form.submit('http://localhost:' + common.port + '/', function(err, res) { if (err) { throw err; } assert.strictEqual(res.statusCode, 200); // unstuck new streams res.resume(); server.close(); // compare progress total to the expected length assert.equal(progress, expectedLength); }); // augment into request oWrite = R.write; R.write = function(chunk) { return oWrite.call(this, chunk, function() { form.emit('progress', chunk); }); }; // track progress form.on('progress', function(chunk) { progress += chunk.length; assert.ok(progress <= expectedLength); }); }); form-data-4.0.1/test/integration/test-set-boundary.js000066400000000000000000000011401470164731200226200ustar00rootroot00000000000000var common = require('../common'); var assert = common.assert; var FormData = require(common.dir.lib + '/form_data'); (function testSetBoundary() { var userBoundary = '---something'; var form = new FormData(); form.setBoundary(userBoundary); assert.equal(form.getBoundary(), userBoundary); })(); (function testUniqueBoundaryPerFormAfterSet() { var userBoundary = '---something'; var formA = new FormData(); formA.setBoundary(userBoundary); var formB = new FormData(); assert.equal(formA.getBoundary(), userBoundary); assert.notEqual(formA.getBoundary(), formB.getBoundary()); })(); form-data-4.0.1/test/integration/test-submit-custom-header.js000066400000000000000000000036461470164731200242620ustar00rootroot00000000000000var common = require('../common'); var assert = common.assert; var http = require('http'); var mime = require('mime-types'); var request = require('request'); var fs = require('fs'); var FormData = require(common.dir.lib + '/form_data'); var IncomingForm = require('formidable').IncomingForm; var remoteFile = 'http://localhost:' + common.staticPort + '/unicycle.jpg'; // wrap non simple values into function // just to deal with ReadStream "autostart" var FIELDS = { 'my_field': { value: 'my_value' }, 'my_buffer': { type: FormData.DEFAULT_CONTENT_TYPE, value: common.defaultTypeValue }, 'my_file': { type: mime.lookup(common.dir.fixture + '/unicycle.jpg'), value: function() { return fs.createReadStream(common.dir.fixture + '/unicycle.jpg'); } }, 'remote_file': { type: mime.lookup(common.dir.fixture + '/unicycle.jpg'), value: function() { return request(remoteFile); } } }; var fieldsPassed = Object.keys(FIELDS).length; var server = http.createServer(function(req, res) { assert.ok(req.headers['x-test-header'], 'test-header-value'); var form = new IncomingForm({uploadDir: common.dir.tmp}); form.parse(req); common.actions.checkForm(form, FIELDS, function(fieldsChecked) { // keep track of number of the processed fields fieldsPassed = fieldsPassed - fieldsChecked; // finish it common.actions.formOnEnd(res); }); }); server.listen(common.port, function() { var form = new FormData(); common.actions.populateFields(form, FIELDS); // custom params object passed to submit form.submit({ port: common.port, path: '/', headers: { 'x-test-header': 'test-header-value' } }, function(error, result) { if (error) { throw error; } assert.strictEqual(result.statusCode, 200); // unstuck streams result.resume(); server.close(); }); }); process.on('exit', function() { assert.strictEqual(fieldsPassed, 0); }); form-data-4.0.1/test/integration/test-submit-custom.js000066400000000000000000000027131470164731200230260ustar00rootroot00000000000000var common = require('../common'); var assert = common.assert; var mime = require('mime-types'); var request = require('request'); var fs = require('fs'); var FormData = require(common.dir.lib + '/form_data'); var remoteFile = 'http://localhost:' + common.staticPort + '/unicycle.jpg'; // wrap non simple values into function // just to deal with ReadStream "autostart" var FIELDS = { 'my_field': { value: 'my_value' }, 'my_buffer': { type: FormData.DEFAULT_CONTENT_TYPE, value: common.defaultTypeValue }, 'my_file': { type: mime.lookup(common.dir.fixture + '/unicycle.jpg'), value: function() { return fs.createReadStream(common.dir.fixture + '/unicycle.jpg'); } }, 'remote_file': { type: mime.lookup(common.dir.fixture + '/unicycle.jpg'), value: function() { return request(remoteFile); } } }; // count total var fieldsPassed = Object.keys(FIELDS).length; // prepare form-receiving http server var server = common.testFields(FIELDS, function(fields){ fieldsPassed = fields; }); server.listen(common.port, function() { var form = new FormData(); common.actions.populateFields(form, FIELDS); // custom params object passed to submit form.submit({ port: common.port, path: '/' }, function(err, res) { if (err) { throw err; } assert.strictEqual(res.statusCode, 200); res.resume(); server.close(); }); }); process.on('exit', function() { assert.strictEqual(fieldsPassed, 0); }); form-data-4.0.1/test/integration/test-submit-https.js000066400000000000000000000022301470164731200226500ustar00rootroot00000000000000var https = require('https'); var common = require('../common'); var assert = common.assert; var FormData = require(common.dir.lib + '/form_data'); var server; /** * Test submission to HTTPS endpoint */ function submitForm() { var form = new FormData(); form.append('field', 'value'); form.submit({ protocol: 'https:', hostname: 'localhost', port: common.httpsPort, pathname: '/', // for self-signed certs on localhost secureOptions: require('constants').SSL_OP_NO_TLSv1_2, ca: common.httpsServerCert }, function(err, res) { if (err) { throw err; } assert.strictEqual(res.statusCode, 200); assert.strictEqual(res.headers['x-success'], 'OK'); // unstuck new streams res.resume(); server.close(); }); } // create https server server = https.createServer({ key: common.httpsServerKey, cert: common.httpsServerCert }, function(req, res) { // old and simple req.on('data', function() {}); req.on('end', function() { res.writeHead(200, {'x-success': 'OK'}); res.end('Great Success'); }); }); // when https server ready submit form server.listen(common.httpsPort, submitForm); form-data-4.0.1/test/integration/test-submit-multi-nocallback.js000066400000000000000000000017221470164731200247340ustar00rootroot00000000000000var common = require('../common'); var assert = common.assert; var http = require('http'); var FormData = require(common.dir.lib + '/form_data'); var IncomingForm = require('formidable').IncomingForm; var times = 10; var server = http.createServer(function(req, res) { // no need to have tmp dir here, since no files being uploaded // but formidable would fail in 0.6 otherwise var form = new IncomingForm({uploadDir: common.dir.tmp}); form.parse(req); form .on('field', common.actions.basicFormOnField) .on('end', function() { res.writeHead(200); res.end('done'); times--; if (times == 0) { server.close(); } }); }); server.listen(common.port, function() { var i; for (i = 0; i < times; i++) { var form = new FormData(); form.append('my_field', 'my_value'); form.submit('http://localhost:' + common.port + '/'); } }); process.on('exit', function() { assert.strictEqual(times, 0); }); form-data-4.0.1/test/integration/test-submit-multi.js000066400000000000000000000024451470164731200226500ustar00rootroot00000000000000var common = require('../common'); var assert = common.assert; var http = require('http'); var FormData = require(common.dir.lib + '/form_data'); var IncomingForm = require('formidable').IncomingForm; var times = 10; var server; /** * Test parallel submissions to the same server */ function submitForm() { var form = new FormData(); form.append('my_field', 'my_value'); form.submit('http://localhost:' + common.port + '/', function(err, res) { if (err) { throw err; } assert.strictEqual(res.statusCode, 200); // Needed for node-0.10.x because Streams2 // more info: http://nodejs.org/api/stream.html#stream_compatibility_with_older_node_versions res.resume(); times--; if (times == 0) { server.close(); } }); } server = http.createServer(function(req, res) { // no need to have tmp dir here, since no files being uploaded // but formidable would fail in 0.6 otherwise var form = new IncomingForm({uploadDir: common.dir.tmp}); form.parse(req); form .on('field', common.actions.basicFormOnField) .on('end', common.actions.formOnEnd.bind(null, res)); }); server.listen(common.port, function() { var i; for (i = 0; i < times; i++) { submitForm(); } }); process.on('exit', function() { assert.strictEqual(times, 0); }); form-data-4.0.1/test/integration/test-submit-readable-stream.js000066400000000000000000000022731470164731200245450ustar00rootroot00000000000000var common = require('../common'); var assert = common.assert; var http = require('http'); var FormData = require(common.dir.lib + '/form_data'); var Readable = require('stream').Readable; var server = http.createServer(function(req, res) { assert.strictEqual(req.headers['Content-Length'], undefined); res.writeHead(200); res.end('done'); }); server.listen(common.port, function() { var form = new FormData(); var util = require('util'); util.inherits(CustomReadable, Readable); /** * Custion readable constructor * @param {Object} opt options * @constructor */ function CustomReadable(opt) { Readable.call(this, opt); this._max = 2; this._index = 1; } CustomReadable.prototype._read = function() { var i = this._index++; // console.error('send back read data'); if (i > this._max) { this.push(null); } else { this.push('' + i); } }; form.append('readable', new CustomReadable()); form.submit('http://localhost:' + common.port + '/', function(err, res) { if (err) { throw err; } assert.strictEqual(res.statusCode, 200); // unstuck new streams res.resume(); server.close(); }); }); form-data-4.0.1/test/integration/test-submit-url-parsing.js000066400000000000000000000017221470164731200237560ustar00rootroot00000000000000var http = require('http'); var https = require('https'); var common = require('../common'); var assert = common.assert; var FormData = require(common.dir.lib + '/form_data'); /** * Test url parsing during submission */ var req; var form = new FormData(); form.append('field', 'value'); // Basic parsing req = form.submit('http://localhost/path', function() {}); assert.strictEqual(req.path, '/path'); assert.ok(req.agent instanceof http.Agent, 'req.agent instanceof http.Agent'); assert.strictEqual(req.getHeader('Host'), 'localhost'); req.abort(); // Non-default port handling req = form.submit('http://localhost:' + common.port, function() {}); assert.strictEqual(req.getHeader('Host'), 'localhost:' + common.port); req.abort(); // HTTPS protocol handling req = form.submit('https://localhost/path', function() {}); assert.ok(req.agent instanceof https.Agent, 'req.agent instanceof https.Agent'); assert.strictEqual(req.getHeader('Host'), 'localhost'); req.abort(); form-data-4.0.1/test/integration/test-submit.js000066400000000000000000000023671470164731200215230ustar00rootroot00000000000000var common = require('../common'); var assert = common.assert; var mime = require('mime-types'); var request = require('request'); var fs = require('fs'); var FormData = require(common.dir.lib + '/form_data'); var remoteFile = 'http://localhost:' + common.staticPort + '/unicycle.jpg'; // wrap non simple values into function // just to deal with ReadStream "autostart" var FIELDS = { 'my_field': { value: 'my_value' }, 'my_buffer': { type: FormData.DEFAULT_CONTENT_TYPE, value: common.defaultTypeValue }, 'my_file': { type: mime.lookup(common.dir.fixture + '/unicycle.jpg'), value: function() { return fs.createReadStream(common.dir.fixture + '/unicycle.jpg'); } }, 'remote_file': { type: mime.lookup(common.dir.fixture + '/unicycle.jpg'), value: function() { return request(remoteFile); } } }; // count total var fieldsPassed = Object.keys(FIELDS).length; // prepare form-receiving http server var server = common.testFields( FIELDS, function(fields){ fieldsPassed = fields; }); server.listen(common.port, function() { var form = new FormData(); common.actions.populateFields(form, FIELDS); common.actions.submit(form, server); }); process.on('exit', function() { assert.strictEqual(fieldsPassed, 0); }); form-data-4.0.1/test/integration/test-to-string.js000066400000000000000000000002661470164731200221420ustar00rootroot00000000000000var common = require('../common'); var assert = common.assert; var FormData = require(common.dir.lib + '/form_data'); assert(new FormData().toString() === '[object FormData]'); form-data-4.0.1/test/run-browser.js000066400000000000000000000006421470164731200171770ustar00rootroot00000000000000var test = require('tape'); var FormData = require('../lib/browser.js'); var form = new FormData(); test('being nice to browser-like environments', function(t) { t.plan(3); t.notEqual(typeof FormData, 'undefined', 'FormData should be defined'); t.equal(typeof form, 'object', 'FormData instance should be object'); t.equal(typeof form.append, 'function', 'FormData instance should have `append` method'); }); form-data-4.0.1/test/run.js000077500000000000000000000035521470164731200155240ustar00rootroot00000000000000#!/usr/bin/env node var path = require('path'); var static = require('./static'); var far = require('far').create(); var farPaths = require('far/lib/paths'); var spawn = require('cross-spawn'); var basePath = process.cwd(); var istanbul = path.join(basePath, './node_modules/.bin/istanbul'); // augment Far to support istanbul if (process.env.running_under_istanbul) { far.constructor.prototype._execute = function(file) { this._printStatus(file); var node = spawn(istanbul, [ 'cover', '--report', 'none', '--print', 'none', '--include-all-sources', '--include-pid', '--root', basePath, file ]); var output = ''; node.stdout.setEncoding('utf8'); node.stderr.setEncoding('utf8'); /** * Collects output delivered in chunks * @param {string} chunk - partial output */ function onOutput(chunk) { if (this._verbose > 1) { process.stderr.write(chunk); } else { output += chunk; } } node.stdout.on('data', onOutput.bind(this)); node.stderr.on('data', onOutput.bind(this)); node.on('exit', function(code) { this._index++; this._printTestResult(file, code, output); this._executeNext(); }.bind(this)); }; } // augment far to work on windows farPaths.expandSync = function(pathList) { var expanded = {}; pathList.forEach(function(p) { p = path.resolve(process.cwd(), p); if (!farPaths.isDirectory(p)) { expanded[p] = true; return; } farPaths .findRecursiveSync(p) .forEach(function(pp) { expanded[pp] = true; }); }); return Object.keys(expanded); }; // continue as normal if (process.env.verbose) { far.verbose(process.env.verbose); } far.add(__dirname); far.include(/test-.*\.js$/); // start static server for all tests static(function() { far.execute(); }); form-data-4.0.1/test/static.js000066400000000000000000000013251470164731200162000ustar00rootroot00000000000000// serves static files var http = require('http'); var fs = require('fs'); var path = require('path'); var mime = require('mime-types'); var common = require('./common'); // prepare tmp folder if (!fs.existsSync(common.dir.tmp)) { fs.mkdirSync(common.dir.tmp); } module.exports = function(callback) { // create http server var httpServer = http.createServer(function(req, res) { var target = path.join(common.dir.fixture, req.url); var stat = fs.statSync(target); res.writeHead(200, { 'Content-Type': mime.lookup(target), 'Content-Length': stat.size }); fs.createReadStream(target).pipe(res); }); httpServer.listen(common.staticPort, callback.bind(undefined, httpServer)); };