Server IP : 127.0.0.2 / Your IP : 3.145.28.3 Web Server : Apache/2.4.18 (Ubuntu) System : User : www-data ( ) PHP Version : 7.0.33-0ubuntu0.16.04.16 Disable Function : disk_free_space,disk_total_space,diskfreespace,dl,exec,fpaththru,getmyuid,getmypid,highlight_file,ignore_user_abord,leak,listen,link,opcache_get_configuration,opcache_get_status,passthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,php_uname,phpinfo,posix_ctermid,posix_getcwd,posix_getegid,posix_geteuid,posix_getgid,posix_getgrgid,posix_getgrnam,posix_getgroups,posix_getlogin,posix_getpgid,posix_getpgrp,posix_getpid,posix,_getppid,posix_getpwnam,posix_getpwuid,posix_getrlimit,posix_getsid,posix_getuid,posix_isatty,posix_kill,posix_mkfifo,posix_setegid,posix_seteuid,posix_setgid,posix_setpgid,posix_setsid,posix_setuid,posix_times,posix_ttyname,posix_uname,pclose,popen,proc_open,proc_close,proc_get_status,proc_nice,proc_terminate,shell_exec,source,show_source,system,virtual MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /usr/lib/nodejs/form-data/ |
Upload File : |
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, 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; }