aboutsummaryrefslogtreecommitdiff
path: root/deps/npm/node_modules/node-gyp/node_modules/request/node_modules/form-data/lib/form_data.js
diff options
context:
space:
mode:
Diffstat (limited to 'deps/npm/node_modules/node-gyp/node_modules/request/node_modules/form-data/lib/form_data.js')
-rw-r--r--deps/npm/node_modules/node-gyp/node_modules/request/node_modules/form-data/lib/form_data.js237
1 files changed, 237 insertions, 0 deletions
diff --git a/deps/npm/node_modules/node-gyp/node_modules/request/node_modules/form-data/lib/form_data.js b/deps/npm/node_modules/node-gyp/node_modules/request/node_modules/form-data/lib/form_data.js
new file mode 100644
index 0000000000..426b06f3b0
--- /dev/null
+++ b/deps/npm/node_modules/node-gyp/node_modules/request/node_modules/form-data/lib/form_data.js
@@ -0,0 +1,237 @@
+var 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) {
+ var append = CombinedStream.prototype.append.bind(this);
+
+ // all that streamy business can't handle numbers
+ if (typeof value == 'number') value = ''+value;
+
+ var header = this._multiPartHeader(field, value);
+ var footer = this._multiPartFooter(field, value);
+
+ append(header);
+ append(value);
+ append(footer);
+
+ this._trackLength(header, value)
+};
+
+FormData.prototype._trackLength = function(header, value) {
+ var valueLength = 0;
+ if (Buffer.isBuffer(value)) {
+ valueLength = value.length;
+ } else if (typeof value === 'string') {
+ valueLength = Buffer.byteLength(value);
+ }
+
+ this._valueLength += valueLength;
+ this._overheadLength +=
+ Buffer.byteLength(header) +
+ + FormData.LINE_BREAK.length;
+
+ // empty or ethier doesn't have path or not an http response
+ if (!value || ( !value.path && !(value.readable && value.hasOwnProperty('httpVersion')) )) {
+ return;
+ }
+
+ this._lengthRetrievers.push(function(next) {
+
+ // check if it's local file
+ 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) {
+ var boundary = this.getBoundary();
+ var header =
+ '--' + boundary + FormData.LINE_BREAK +
+ 'Content-Disposition: form-data; name="' + field + '"';
+
+ // fs- and request- streams have path property
+ // TODO: Use request's response mime-type
+ if (value.path) {
+ header +=
+ '; filename="' + path.basename(value.path) + '"' + FormData.LINE_BREAK +
+ 'Content-Type: ' + mime.lookup(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) {
+ 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;
+};
+
+FormData.prototype.getLengthSync = function() {
+ var knownLength = this._overheadLength + this._valueLength;
+
+ if (this._streams.length) {
+ knownLength += this._lastBoundary().length;
+ }
+
+ 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(url, 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:') {
+ // override default port
+ if (!parsedUrl.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));
+};