Skip to content

Commit

Permalink
Merge pull request #22 from alexindigo/master
Browse files Browse the repository at this point in the history
Custom params for form.submit() should cover most edge cases.
  • Loading branch information
alexindigo committed Jan 8, 2013
2 parents 7e98fb9 + 4581140 commit 5277bb3
Show file tree
Hide file tree
Showing 6 changed files with 203 additions and 22 deletions.
13 changes: 13 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,17 @@ form.submit('http://example.com/', function(err, res) {
});
```

For edge cases, like POST request to URL with query string or to pass HTTP auth creadentials, 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);
});
```


[xhr2-fd]: http://dev.w3.org/2006/webapi/XMLHttpRequest-2/Overview.html#the-formdata-interface
54 changes: 41 additions & 13 deletions lib/form_data.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ FormData.prototype.append = function(field, value, options) {

FormData.prototype._trackLength = function(header, value, options) {
var valueLength = 0;

// used w/ trackLengthSync(), 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
Expand Down Expand Up @@ -232,21 +232,37 @@ FormData.prototype.getLength = function(cb) {
});
};

FormData.prototype.submit = function(url, cb) {
FormData.prototype.submit = function(params, cb) {
this.getLength(function(err, length) {

var request
, parsedUrl = parseUrl(url)
, options = {
method: 'post',
port: parsedUrl.port || 80,
path: parsedUrl.pathname,
headers: this.getHeaders({'Content-Length': length}),
host: parsedUrl.hostname
};

if (parsedUrl.protocol == 'https:') {
, 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 (!parsedUrl.port) options.port = 443;
if (!params.port) options.port = 443;
request = https.request(options);
} else {
request = http.request(options);
Expand All @@ -261,3 +277,15 @@ FormData.prototype.submit = function(url, cb) {
return request;
}.bind(this));
};

/*
* 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;
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"author": "Felix Geisendörfer <felix@debuggable.com> (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.0.5",
"version": "0.0.6",
"repository": {
"type": "git",
"url": "git://github.com/felixge/node-form-data.git"
Expand Down
17 changes: 13 additions & 4 deletions test/integration/test-pipe.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,20 @@ 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: new Buffer([1, 2, 3])},
{name: 'my_file', value: fs.createReadStream(common.dir.fixture + '/unicycle.jpg')},
{name: 'remote_file', value: request(remoteFile) }
{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) {

// formidable is broken so let's do it manual way
// formidable is fixed on github
// but still 7 month old in npm
//
// var form = new IncomingForm();
// form.uploadDir = common.dir.tmp;
Expand Down Expand Up @@ -66,6 +70,7 @@ var server = http.createServer(function(req, res) {
var field = FIELDS.shift();
assert.ok( data.indexOf('form-data; name="'+field.name+'"') != -1 );
assert.ok( data.indexOf('; filename="'+path.basename(field.value.path)+'"') != -1 );

// check for unicycle.jpg traces
assert.ok( data.indexOf('2005:06:21 01:44:12') != -1 );
assert.ok( data.indexOf('Content-Type: '+mime.lookup(field.value.path) ) != -1 );
Expand All @@ -89,6 +94,10 @@ var server = http.createServer(function(req, res) {
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);
});

Expand Down
121 changes: 121 additions & 0 deletions test/integration/test-submit-custom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
var 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) {

// formidable is fixed on github
// but still 7 month old in npm
//
// var form = new IncomingForm();
// form.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));
// // mime.lookup file.NAME == 'my_file' ?
// assert.strictEqual(file.type, mime.lookup(file.name));
// })
// .on('end', function() {
// res.writeHead(200);
// res.end('done');
// });

// temp workaround
var data = '';
req.setEncoding('utf8');
req.on('data', function(d) {
data += d;
});
req.on('end', function() {
// check for the fields' traces

// 1st field : my_field
var field = FIELDS.shift();
assert.ok( data.indexOf('form-data; name="'+field.name+'"') != -1 );
assert.ok( data.indexOf(field.value) != -1 );

// 2nd field : my_buffer
var field = FIELDS.shift();
assert.ok( data.indexOf('form-data; name="'+field.name+'"') != -1 );
assert.ok( data.indexOf(field.value) != -1 );

// 3rd field : my_file
var field = FIELDS.shift();
assert.ok( data.indexOf('form-data; name="'+field.name+'"') != -1 );
assert.ok( data.indexOf('; filename="'+path.basename(field.value.path)+'"') != -1 );
// check for unicycle.jpg traces
assert.ok( data.indexOf('2005:06:21 01:44:12') != -1 );
assert.ok( data.indexOf('Content-Type: '+mime.lookup(field.value.path) ) != -1 );

// 4th field : remote_file
var field = FIELDS.shift();
assert.ok( data.indexOf('form-data; name="'+field.name+'"') != -1 );
assert.ok( data.indexOf('; filename="'+path.basename(field.value.path)+'"') != -1 );
// check for http://nodejs.org/images/logo.png traces
assert.ok( data.indexOf('ImageReady') != -1 );
assert.ok( data.indexOf('Content-Type: '+mime.lookup(remoteFile) ) != -1 );

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);
});

// custom params object passed to submit
form.submit({
port: common.port,
path: '/'
}, function(err, res) {

if (err) {
throw err;
}

assert.strictEqual(res.statusCode, 200);
server.close();
});

});

process.on('exit', function() {
assert.strictEqual(FIELDS.length, 0);
});
18 changes: 14 additions & 4 deletions test/integration/test-submit.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,20 @@ 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: new Buffer([1, 2, 3])},
{name: 'my_file', value: fs.createReadStream(common.dir.fixture + '/unicycle.jpg') },
{name: 'remote_file', value: request(remoteFile) }
{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) {

// formidable is broken so let's do it manual way
// formidable is fixed on github
// but still 7 month old in npm
//
// var form = new IncomingForm();
// form.uploadDir = common.dir.tmp;
Expand Down Expand Up @@ -85,8 +89,14 @@ var server = http.createServer(function(req, res) {
});

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);
});

Expand Down

0 comments on commit 5277bb3

Please sign in to comment.