pax_global_header00006660000000000000000000000064121666036110014514gustar00rootroot0000000000000052 comment=fdc52f3fa32198da44644bb158e6f5764feb3767 node-form-data-0.1.0/000077500000000000000000000000001216660361100143075ustar00rootroot00000000000000node-form-data-0.1.0/.gitignore000066400000000000000000000000711216660361100162750ustar00rootroot00000000000000*.un~ *.sublime-* /node_modules/* /test/tmp /.idea *.iml node-form-data-0.1.0/.npmignore000066400000000000000000000001661216660361100163110ustar00rootroot00000000000000*.un~ *.iml *.sublime-* /node_modules/ /test/ /.idea /.gitignore /.npmignore /.travis.yml /Makefile /sftp-config.json node-form-data-0.1.0/.travis.yml000066400000000000000000000001051216660361100164140ustar00rootroot00000000000000language: node_js node_js: - "0.6" - "0.8" - "0.10" - "0.11" node-form-data-0.1.0/License000066400000000000000000000021361216660361100156160ustar00rootroot00000000000000Copyright (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. node-form-data-0.1.0/Makefile000066400000000000000000000000711216660361100157450ustar00rootroot00000000000000SHELL := /bin/bash test: @./test/run.js .PHONY: test node-form-data-0.1.0/Readme.md000066400000000000000000000073171216660361100160360ustar00rootroot00000000000000# Form-Data [![Build Status](https://travis-ci.org/felixge/node-form-data.png?branch=master)](https://travis-ci.org/felixge/node-form-data) [![Dependency Status](https://gemnasium.com/felixge/node-form-data.png)](https://gemnasium.com/felixge/node-form-data) A module to create readable ```"multipart/form-data"``` streams. Can be used to submit forms and file uploads to other web applications. The API of this module 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 ## Install ``` npm install 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 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, 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', contentType: 'image/jpg', knownLength: 19806 }); form.submit('http://example.com/', function(err, res) { if (err) throw err; console.log('Done'); }); }); ``` 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); }); ``` ## Notes - ```getLengthSync()``` method DOESN'T calculate length for streams, use ```knownLength``` options as workaround. ## TODO - Add new streams (0.10) support and try really hard not to break it for 0.8.x. ## License Form-Data is licensed under the MIT license. node-form-data-0.1.0/lib/000077500000000000000000000000001216660361100150555ustar00rootroot00000000000000node-form-data-0.1.0/lib/form_data.js000066400000000000000000000205231216660361100173510ustar00rootroot00000000000000var 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 mime = require('mime'); var async = require('async'); module.exports = FormData; function FormData() { this._overheadLength = 0; this._valueLength = 0; this._lengthRetrievers = []; CombinedStream.call(this); } util.inherits(FormData, CombinedStream); FormData.LINE_BREAK = '\r\n'; FormData.prototype.append = function(field, value, options) { options = 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 (util.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(field, value, options); 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 if (!value || ( !value.path && !(value.readable && value.hasOwnProperty('httpVersion')) )) { return; } // no need to bother with the length if (!options.knownLength) this._lengthRetrievers.push(function(next) { if (value.hasOwnProperty('fd')) { fs.stat(value.path, function(err, stat) { if (err) { next(err); return; } next(null, stat.size); }); // or http response } else if (value.hasOwnProperty('httpVersion')) { next(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(); next(null, +response.headers['content-length']); }); value.resume(); // something else } else { next('Unknown stream'); } }); }; FormData.prototype._multiPartHeader = function(field, value, options) { var boundary = this.getBoundary(); var header = ''; // custom header specified (as string)? // it becomes responsible for boundary // (e.g. to handle extra CRLFs on .NET servers) if (options.header != null) { header = options.header; } else { header += '--' + boundary + FormData.LINE_BREAK + 'Content-Disposition: form-data; name="' + field + '"'; // fs- and request- streams have path property // or use custom filename and/or contentType // TODO: Use request's response mime-type if (options.filename || value.path) { header += '; filename="' + path.basename(options.filename || value.path) + '"' + FormData.LINE_BREAK + 'Content-Type: ' + (options.contentType || mime.lookup(options.filename || value.path)); // http response has not } else if (value.readable && value.hasOwnProperty('httpVersion')) { header += '; filename="' + path.basename(value.client._httpMessage.path) + '"' + FormData.LINE_BREAK + 'Content-Type: ' + value.headers['content-type']; } header += FormData.LINE_BREAK + FormData.LINE_BREAK; } return header; }; FormData.prototype._multiPartFooter = function(field, value, options) { 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.prototype.getHeaders = function(userHeaders) { var formHeaders = { 'content-type': 'multipart/form-data; boundary=' + this.getBoundary() }; for (var header in userHeaders) { formHeaders[header.toLowerCase()] = userHeaders[header]; } return formHeaders; } FormData.prototype.getCustomHeaders = function(contentType) { contentType = contentType ? contentType : 'multipart/form-data'; var formHeaders = { 'content-type': contentType + '; boundary=' + this.getBoundary(), 'content-length': this.getLengthSync() }; return formHeaders; } FormData.prototype.getBoundary = function() { if (!this._boundary) { this._generateBoundary(); } return this._boundary; }; 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(debug) { 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/felixge/node-form-data/issues/40 if (this._lengthRetrievers.length) { // Some async length retrivers 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; }; FormData.prototype.getLength = function(cb) { var knownLength = this._overheadLength + this._valueLength; if (this._streams.length) { knownLength += this._lastBoundary().length; } if (!this._lengthRetrievers.length) { process.nextTick(cb.bind(this, null, knownLength)); return; } async.parallel(this._lengthRetrievers, function(err, values) { if (err) { cb(err); return; } values.forEach(function(length) { knownLength += length; }); cb(null, knownLength); }); }; FormData.prototype.submit = function(params, cb) { this.getLength(function(err, length) { var request , options , defaults = { method : 'post', port : 80, headers: this.getHeaders({'Content-Length': length}) }; // 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 }, defaults); } else // use custom params { options = populate(params, defaults); } // https if specified, fallback to http in any other case if (params.protocol == 'https:') { // override default port if (!params.port) options.port = 443; request = https.request(options); } else { request = http.request(options); } this.pipe(request); if (cb) { request.on('error', cb); request.on('response', cb.bind(this, null)); } return request; }.bind(this)); }; FormData.prototype._error = function(err) { if (this.error) return; this.error = err; this.pause(); this.emit('error', err); }; /* * Santa's little helpers */ // populates missing values function populate(dst, src) { for (var prop in src) { if (!dst[prop]) dst[prop] = src[prop]; } return dst; } node-form-data-0.1.0/package.json000066400000000000000000000013341216660361100165760ustar00rootroot00000000000000{ "author": "Felix Geisendörfer (http://debuggable.com/)", "name": "form-data", "description": "A module to create readable \"multipart/form-data\" streams. Can be used to submit forms and file uploads to other web applications.", "version": "0.1.0", "repository": { "type": "git", "url": "git://github.com/felixge/node-form-data.git" }, "main": "./lib/form_data", "scripts": { "test": "node test/run.js" }, "engines": { "node": ">= 0.6" }, "dependencies": { "combined-stream": "~0.0.4", "mime": "~1.2.9", "async": "~0.2.9" }, "devDependencies": { "fake": "~0.2.2", "far": "~0.0.7", "formidable": "~1.0.14", "request": "~2.22.0" } } node-form-data-0.1.0/test/000077500000000000000000000000001216660361100152665ustar00rootroot00000000000000node-form-data-0.1.0/test/common.js000066400000000000000000000004531216660361100171160ustar00rootroot00000000000000var common = module.exports; var path = require('path'); var rootDir = path.join(__dirname, '..'); common.dir = { lib: rootDir + '/lib', fixture: rootDir + '/test/fixture', tmp: rootDir + '/test/tmp', }; common.assert = require('assert'); common.fake = require('fake'); common.port = 8432; node-form-data-0.1.0/test/fixture/000077500000000000000000000000001216660361100167545ustar00rootroot00000000000000node-form-data-0.1.0/test/fixture/bacon.txt000066400000000000000000000000241216660361100205730ustar00rootroot00000000000000Bacon is delicious. node-form-data-0.1.0/test/fixture/unicycle.jpg000066400000000000000000000465361216660361100213070ustar00rootroot00000000000000JFIFHH(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{|node-form-data-0.1.0/test/integration/000077500000000000000000000000001216660361100176115ustar00rootroot00000000000000node-form-data-0.1.0/test/integration/test-custom-filename.js000066400000000000000000000023671216660361100242240ustar00rootroot00000000000000/* 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 http = require('http'); var fs = require('fs'); var FormData = require(common.dir.lib + '/form_data'); var IncomingForm = require('formidable').IncomingForm; 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); form .on('file', function(name, file) { assert.strictEqual(name, 'my_file'); assert.strictEqual(file.name, options.filename); assert.strictEqual(file.type, options.contentType); }) .on('end', function() { res.writeHead(200); res.end('done'); }); }); server.listen(common.port, function() { var form = new FormData(); form.append('my_file', fs.createReadStream(common.dir.fixture + '/unicycle.jpg'), options); 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(); }); }); node-form-data-0.1.0/test/integration/test-custom-headers.js000066400000000000000000000026001216660361100240450ustar00rootroot00000000000000/* 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) { var data = ''; assert.ok( typeof req.headers['content-length'] !== 'undefined' ); assert.equal(req.headers['content-length'], expectedLength); 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; 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(); }); }); node-form-data-0.1.0/test/integration/test-errors.js000066400000000000000000000032021216660361100224350ustar00rootroot00000000000000var common = require('../common'); var assert = common.assert; var FormData = require(common.dir.lib + '/form_data'); var fake = require('fake').create(); var fs = require('fs'); // https://github.com/felixge/node-form-data/issues/38 (function testAppendArray() { var form = new FormData(); var callback = fake.callback(arguments.callee.name + '-onError-append'); fake.expectAnytime(callback, ['Arrays are not supported.']); form.on('error', function(err) { // workaroud 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(arguments.callee.name + '-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); })(); node-form-data-0.1.0/test/integration/test-form-get-length-sync.js000066400000000000000000000033221216660361100250750ustar00rootroot00000000000000var common = require('../common'); var assert = common.assert; var FormData = require(common.dir.lib + '/form_data'); var fake = require('fake').create(); var fs = require('fs'); (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); })(); node-form-data-0.1.0/test/integration/test-form-get-length.js000066400000000000000000000043431216660361100241270ustar00rootroot00000000000000var common = require('../common'); var assert = common.assert; var FormData = require(common.dir.lib + '/form_data'); var fake = require('fake').create(); var fs = require('fs'); (function testEmptyForm() { var form = new FormData(); var callback = fake.callback(arguments.callee.name + '-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(arguments.callee.name + '-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(arguments.callee.name + '-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 + '/bacon.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(arguments.callee.name + '-getLength'); fake.expectAnytime(callback, [null, expectedLength]); form.getLength(callback); })(); node-form-data-0.1.0/test/integration/test-get-boundary.js000066400000000000000000000007411216660361100235260ustar00rootroot00000000000000var 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()); })(); node-form-data-0.1.0/test/integration/test-http-response.js000066400000000000000000000037631216660361100237500ustar00rootroot00000000000000var common = require('../common'); var assert = common.assert; var http = require('http'); var path = require('path'); var mime = require('mime'); var request = require('request'); var parseUrl = require('url').parse; var fs = require('fs'); var FormData = require(common.dir.lib + '/form_data'); var IncomingForm = require('formidable').IncomingForm; var remoteFile = 'http://nodejs.org/images/logo.png'; var FIELDS; var server; var parsedUrl = parseUrl(remoteFile) , options = { method: 'get', port: parsedUrl.port || 80, path: parsedUrl.pathname, host: parsedUrl.hostname } ; http.request(options, function(res) { FIELDS = [ {name: 'my_field', value: 'my_value'}, {name: 'my_buffer', value: new Buffer([1, 2, 3])}, {name: 'remote_file', value: res } ]; var form = new FormData(); FIELDS.forEach(function(field) { form.append(field.name, field.value); }); server.listen(common.port, function() { 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(); }); }); }).end(); server = http.createServer(function(req, res) { var form = new IncomingForm({uploadDir: common.dir.tmp}); form.parse(req); form .on('field', function(name, value) { var field = FIELDS.shift(); assert.strictEqual(name, field.name); assert.strictEqual(value, field.value+''); }) .on('file', function(name, file) { var field = FIELDS.shift(); assert.strictEqual(name, field.name); // http response doesn't have path property assert.strictEqual(file.name, path.basename(field.value.path || remoteFile)); assert.strictEqual(file.type, mime.lookup(file.name)); }) .on('end', function() { res.writeHead(200); res.end('done'); }); }); process.on('exit', function() { assert.strictEqual(FIELDS.length, 0); }); node-form-data-0.1.0/test/integration/test-pipe.js000066400000000000000000000040711216660361100220630ustar00rootroot00000000000000var common = require('../common'); var assert = common.assert; var http = require('http'); var path = require('path'); var mime = require('mime'); var request = require('request'); var fs = require('fs'); var FormData = require(common.dir.lib + '/form_data'); var IncomingForm = require('formidable').IncomingForm; var remoteFile = 'http://nodejs.org/images/logo.png'; // wrap non simple values into function // just to deal with ReadStream "autostart" // Can't wait for 0.10 var FIELDS = [ {name: 'my_field', value: 'my_value'}, {name: 'my_buffer', value: function(){ return new Buffer([1, 2, 3])} }, {name: 'my_file', value: function(){ return fs.createReadStream(common.dir.fixture + '/unicycle.jpg')} }, {name: 'remote_file', value: function(){ return request(remoteFile)} } ]; var server = http.createServer(function(req, res) { var form = new IncomingForm({uploadDir: common.dir.tmp}); form.parse(req); form .on('field', function(name, value) { var field = FIELDS.shift(); assert.strictEqual(name, field.name); assert.strictEqual(value, field.value+''); }) .on('file', function(name, file) { var field = FIELDS.shift(); assert.strictEqual(name, field.name); assert.strictEqual(file.name, path.basename(field.value.path)); assert.strictEqual(file.type, mime.lookup(file.name)); }) .on('end', function() { res.writeHead(200); res.end('done'); }); }); server.listen(common.port, function() { var form = new FormData(); FIELDS.forEach(function(field) { // important to append ReadStreams within the same tick if ((typeof field.value == 'function')) { field.value = field.value(); } form.append(field.name, field.value); }); var request = http.request({ method: 'post', port: common.port, path: '/upload', headers: form.getHeaders() }); form.pipe(request); request.on('response', function(res) { // unstuck new streams res.resume(); server.close(); }); }); process.on('exit', function() { assert.strictEqual(FIELDS.length, 0); }); node-form-data-0.1.0/test/integration/test-submit-custom.js000066400000000000000000000040761216660361100237460ustar00rootroot00000000000000var common = require('../common'); var assert = common.assert; var http = require('http'); var path = require('path'); var mime = require('mime'); var request = require('request'); var fs = require('fs'); var FormData = require(common.dir.lib + '/form_data'); var IncomingForm = require('formidable').IncomingForm; var remoteFile = 'http://nodejs.org/images/logo.png'; // wrap non simple values into function // just to deal with ReadStream "autostart" // Can't wait for 0.10 var FIELDS = { 'my_field': 'my_value', 'my_buffer': function(){ return new Buffer([1, 2, 3]); }, 'my_file': function(){ return fs.createReadStream(common.dir.fixture + '/unicycle.jpg'); }, 'remote_file': function(){ return request(remoteFile); } }; var fieldsPassed = 4; var server = http.createServer(function(req, res) { var form = new IncomingForm({uploadDir: common.dir.tmp}); form.parse(req); form .on('field', function(name, value) { fieldsPassed--; var field = FIELDS[name]; assert.ok(field); assert.strictEqual(value, ''+field); }) .on('file', function(name, file) { fieldsPassed--; var field = FIELDS[name]; assert.ok(field); assert.strictEqual(file.name, path.basename(field.path)); assert.strictEqual(file.type, mime.lookup(file.name)); }) .on('end', function() { res.writeHead(200); res.end('done'); }); }); server.listen(common.port, function() { var form = new FormData(); for (var name in FIELDS) { if (!FIELDS.hasOwnProperty(name)) continue; // important to append ReadStreams within the same tick if ((typeof FIELDS[name] == 'function')) { FIELDS[name] = FIELDS[name](); } form.append(name, FIELDS[name]); } // custom params object passed to submit form.submit({ port: common.port, path: '/' }, function(err, res) { if (err) { throw err; } assert.strictEqual(res.statusCode, 200); // unstuck new streams res.resume(); server.close(); }); }); process.on('exit', function() { assert.strictEqual(fieldsPassed, 0); }); node-form-data-0.1.0/test/integration/test-submit.js000066400000000000000000000040201216660361100224230ustar00rootroot00000000000000var common = require('../common'); var assert = common.assert; var http = require('http'); var path = require('path'); var mime = require('mime'); var request = require('request'); var fs = require('fs'); var FormData = require(common.dir.lib + '/form_data'); var IncomingForm = require('formidable').IncomingForm; var remoteFile = 'http://nodejs.org/images/logo.png'; // wrap non simple values into function // just to deal with ReadStream "autostart" // Can't wait for 0.10 var FIELDS = { 'my_field': 'my_value', 'my_buffer': function(){ return new Buffer([1, 2, 3]); }, 'my_file': function(){ return fs.createReadStream(common.dir.fixture + '/unicycle.jpg'); }, 'remote_file': function(){ return request(remoteFile); } }; var fieldsPassed = 4; var server = http.createServer(function(req, res) { var form = new IncomingForm({uploadDir: common.dir.tmp}); form.parse(req); form .on('field', function(name, value) { fieldsPassed--; var field = FIELDS[name]; assert.ok(field); assert.strictEqual(value, ''+field); }) .on('file', function(name, file) { fieldsPassed--; var field = FIELDS[name]; assert.ok(field); assert.strictEqual(file.name, path.basename(field.path)); assert.strictEqual(file.type, mime.lookup(file.name)); }) .on('end', function() { res.writeHead(200); res.end('done'); }); }); server.listen(common.port, function() { var form = new FormData(); for (var name in FIELDS) { if (!FIELDS.hasOwnProperty(name)) continue; // important to append ReadStreams within the same tick if ((typeof FIELDS[name] == 'function')) { FIELDS[name] = FIELDS[name](); } form.append(name, FIELDS[name]); } 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(); }); }); process.on('exit', function() { assert.strictEqual(fieldsPassed, 0); }); node-form-data-0.1.0/test/run.js000077500000000000000000000002731216660361100164350ustar00rootroot00000000000000#!/usr/bin/env node var far = require('far').create(); if (process.env.verbose) { far.verbose(process.env.verbose); } far.add(__dirname); far.include(/test-.*\.js$/); far.execute(); node-form-data-0.1.0/test/tmp/000077500000000000000000000000001216660361100160665ustar00rootroot00000000000000node-form-data-0.1.0/test/tmp/.empty000066400000000000000000000000001216660361100172130ustar00rootroot00000000000000