Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 76 additions & 68 deletions lib/form_data.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ var async = require('async');
module.exports = FormData;
function FormData() {
if (!(this instanceof FormData)) {
throw new TypeError("Failed to construct 'FormData': Please use the 'new' operator, this object constructor cannot be called as a function.")
throw new TypeError('Failed to construct FormData: Please use the _new_ operator, this object constructor cannot be called as a function.');
}

this._overheadLength = 0;
this._valueLength = 0;
this._lengthRetrievers = [];
Expand All @@ -33,7 +33,9 @@ FormData.prototype.append = function(field, value, options) {
var append = CombinedStream.prototype.append.bind(this);

// all that streamy business can't handle numbers
if (typeof value == 'number') value = ''+value;
if (typeof value == 'number') {
value = ''+value;
}

// https://github.com/felixge/node-form-data/issues/38
if (util.isArray(value)) {
Expand Down Expand Up @@ -83,60 +85,62 @@ FormData.prototype._trackLength = function(header, value, options) {

// no need to bother with the length
if (!options.knownLength)
this._lengthRetrievers.push(function(next) {

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
next(null, value.end+1 - (value.start ? value.start : 0));
{
this._lengthRetrievers.push(function(next) {

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
next(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) {
next(err);
return;
}

// update final size based on the range options
fileSize = stat.size - (value.start ? value.start : 0);
next(null, fileSize);
});
}

// 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();

// not that fast snoopy
// something else
} else {
// still need to fetch file size from fs
fs.stat(value.path, function(err, stat) {

var fileSize;

if (err) {
next(err);
return;
}

// update final size based on the range options
fileSize = stat.size - (value.start ? value.start : 0);
next(null, fileSize);
});
next('Unknown stream');
}

// 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) {
Expand Down Expand Up @@ -189,11 +193,11 @@ FormData.prototype._multiPartHeader = function(field, value, options) {
contents += prop + ': ' + headers[prop].join('; ') + FormData.LINE_BREAK;
}
}

return '--' + this.getBoundary() + FormData.LINE_BREAK + contents + FormData.LINE_BREAK;
};

FormData.prototype._multiPartFooter = function(field, value, options) {
FormData.prototype._multiPartFooter = function(field, value) {
return function(next) {
var footer = FormData.LINE_BREAK;

Expand All @@ -211,16 +215,19 @@ FormData.prototype._lastBoundary = function() {
};

FormData.prototype.getHeaders = function(userHeaders) {
var header;
var formHeaders = {
'content-type': 'multipart/form-data; boundary=' + this.getBoundary()
};

for (var header in userHeaders) {
formHeaders[header.toLowerCase()] = userHeaders[header];
for (header in userHeaders) {
if (userHeaders.hasOwnProperty(header)) {
formHeaders[header.toLowerCase()] = userHeaders[header];
}
}

return formHeaders;
}
};

FormData.prototype.getCustomHeaders = function(contentType) {
contentType = contentType ? contentType : 'multipart/form-data';
Expand All @@ -231,7 +238,7 @@ FormData.prototype.getCustomHeaders = function(contentType) {
};

return formHeaders;
}
};

FormData.prototype.getBoundary = function() {
if (!this._boundary) {
Expand All @@ -255,7 +262,7 @@ FormData.prototype._generateBoundary = function() {
// 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) {
FormData.prototype.getLengthSync = function() {
var knownLength = this._overheadLength + this._valueLength;

// Don't get confused, there are 3 "internal" streams for each keyval pair
Expand Down Expand Up @@ -302,7 +309,6 @@ FormData.prototype.getLength = function(cb) {
};

FormData.prototype.submit = function(params, cb) {

var request
, options
, defaults = {
Expand Down Expand Up @@ -358,11 +364,11 @@ FormData.prototype.submit = function(params, cb) {
};

FormData.prototype._error = function(err) {
if (this.error) return;

this.error = err;
this.pause();
this.emit('error', err);
if (!this.error) {
this.error = err;
this.pause();
this.emit('error', err);
}
};

/*
Expand All @@ -372,7 +378,9 @@ FormData.prototype._error = function(err) {
// populates missing values
function populate(dst, src) {
for (var prop in src) {
if (!dst[prop]) dst[prop] = src[prop];
if (src.hasOwnProperty(prop) && !dst[prop]) {
dst[prop] = src[prop];
}
}
return dst;
}