index.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. module.exports = (function() {
  2. var __MODS__ = {};
  3. var __DEFINE__ = function(modId, func, req) { var m = { exports: {}, _tempexports: {} }; __MODS__[modId] = { status: 0, func: func, req: req, m: m }; };
  4. var __REQUIRE__ = function(modId, source) { if(!__MODS__[modId]) return require(source); if(!__MODS__[modId].status) { var m = __MODS__[modId].m; m._exports = m._tempexports; var desp = Object.getOwnPropertyDescriptor(m, "exports"); if (desp && desp.configurable) Object.defineProperty(m, "exports", { set: function (val) { if(typeof val === "object" && val !== m._exports) { m._exports.__proto__ = val.__proto__; Object.keys(val).forEach(function (k) { m._exports[k] = val[k]; }); } m._tempexports = val }, get: function () { return m._tempexports; } }); __MODS__[modId].status = 1; __MODS__[modId].func(__MODS__[modId].req, m, m.exports); } return __MODS__[modId].m.exports; };
  5. var __REQUIRE_WILDCARD__ = function(obj) { if(obj && obj.__esModule) { return obj; } else { var newObj = {}; if(obj != null) { for(var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) newObj[k] = obj[k]; } } newObj.default = obj; return newObj; } };
  6. var __REQUIRE_DEFAULT__ = function(obj) { return obj && obj.__esModule ? obj.default : obj; };
  7. __DEFINE__(1662612701774, function(require, module, exports) {
  8. var CombinedStream = require('combined-stream');
  9. var util = require('util');
  10. var path = require('path');
  11. var http = require('http');
  12. var https = require('https');
  13. var parseUrl = require('url').parse;
  14. var fs = require('fs');
  15. var Stream = require('stream').Stream;
  16. var mime = require('mime-types');
  17. var asynckit = require('asynckit');
  18. var populate = require('./populate.js');
  19. // Public API
  20. module.exports = FormData;
  21. // make it a Stream
  22. util.inherits(FormData, CombinedStream);
  23. /**
  24. * Create readable "multipart/form-data" streams.
  25. * Can be used to submit forms
  26. * and file uploads to other web applications.
  27. *
  28. * @constructor
  29. * @param {Object} options - Properties to be added/overriden for FormData and CombinedStream
  30. */
  31. function FormData(options) {
  32. if (!(this instanceof FormData)) {
  33. return new FormData(options);
  34. }
  35. this._overheadLength = 0;
  36. this._valueLength = 0;
  37. this._valuesToMeasure = [];
  38. CombinedStream.call(this);
  39. options = options || {};
  40. for (var option in options) {
  41. this[option] = options[option];
  42. }
  43. }
  44. FormData.LINE_BREAK = '\r\n';
  45. FormData.DEFAULT_CONTENT_TYPE = 'application/octet-stream';
  46. FormData.prototype.append = function(field, value, options) {
  47. options = options || {};
  48. // allow filename as single option
  49. if (typeof options == 'string') {
  50. options = {filename: options};
  51. }
  52. var append = CombinedStream.prototype.append.bind(this);
  53. // all that streamy business can't handle numbers
  54. if (typeof value == 'number') {
  55. value = '' + value;
  56. }
  57. // https://github.com/felixge/node-form-data/issues/38
  58. if (util.isArray(value)) {
  59. // Please convert your array into string
  60. // the way web server expects it
  61. this._error(new Error('Arrays are not supported.'));
  62. return;
  63. }
  64. var header = this._multiPartHeader(field, value, options);
  65. var footer = this._multiPartFooter();
  66. append(header);
  67. append(value);
  68. append(footer);
  69. // pass along options.knownLength
  70. this._trackLength(header, value, options);
  71. };
  72. FormData.prototype._trackLength = function(header, value, options) {
  73. var valueLength = 0;
  74. // used w/ getLengthSync(), when length is known.
  75. // e.g. for streaming directly from a remote server,
  76. // w/ a known file a size, and not wanting to wait for
  77. // incoming file to finish to get its size.
  78. if (options.knownLength != null) {
  79. valueLength += +options.knownLength;
  80. } else if (Buffer.isBuffer(value)) {
  81. valueLength = value.length;
  82. } else if (typeof value === 'string') {
  83. valueLength = Buffer.byteLength(value);
  84. }
  85. this._valueLength += valueLength;
  86. // @check why add CRLF? does this account for custom/multiple CRLFs?
  87. this._overheadLength +=
  88. Buffer.byteLength(header) +
  89. FormData.LINE_BREAK.length;
  90. // empty or either doesn't have path or not an http response or not a stream
  91. if (!value || ( !value.path && !(value.readable && value.hasOwnProperty('httpVersion')) && !(value instanceof Stream))) {
  92. return;
  93. }
  94. // no need to bother with the length
  95. if (!options.knownLength) {
  96. this._valuesToMeasure.push(value);
  97. }
  98. };
  99. FormData.prototype._lengthRetriever = function(value, callback) {
  100. if (value.hasOwnProperty('fd')) {
  101. // take read range into a account
  102. // `end` = Infinity –> read file till the end
  103. //
  104. // TODO: Looks like there is bug in Node fs.createReadStream
  105. // it doesn't respect `end` options without `start` options
  106. // Fix it when node fixes it.
  107. // https://github.com/joyent/node/issues/7819
  108. if (value.end != undefined && value.end != Infinity && value.start != undefined) {
  109. // when end specified
  110. // no need to calculate range
  111. // inclusive, starts with 0
  112. callback(null, value.end + 1 - (value.start ? value.start : 0));
  113. // not that fast snoopy
  114. } else {
  115. // still need to fetch file size from fs
  116. fs.stat(value.path, function(err, stat) {
  117. var fileSize;
  118. if (err) {
  119. callback(err);
  120. return;
  121. }
  122. // update final size based on the range options
  123. fileSize = stat.size - (value.start ? value.start : 0);
  124. callback(null, fileSize);
  125. });
  126. }
  127. // or http response
  128. } else if (value.hasOwnProperty('httpVersion')) {
  129. callback(null, +value.headers['content-length']);
  130. // or request stream http://github.com/mikeal/request
  131. } else if (value.hasOwnProperty('httpModule')) {
  132. // wait till response come back
  133. value.on('response', function(response) {
  134. value.pause();
  135. callback(null, +response.headers['content-length']);
  136. });
  137. value.resume();
  138. // something else
  139. } else {
  140. callback('Unknown stream');
  141. }
  142. };
  143. FormData.prototype._multiPartHeader = function(field, value, options) {
  144. // custom header specified (as string)?
  145. // it becomes responsible for boundary
  146. // (e.g. to handle extra CRLFs on .NET servers)
  147. if (typeof options.header == 'string') {
  148. return options.header;
  149. }
  150. var contentDisposition = this._getContentDisposition(value, options);
  151. var contentType = this._getContentType(value, options);
  152. var contents = '';
  153. var headers = {
  154. // add custom disposition as third element or keep it two elements if not
  155. 'Content-Disposition': ['form-data', 'name="' + field + '"'].concat(contentDisposition || []),
  156. // if no content type. allow it to be empty array
  157. 'Content-Type': [].concat(contentType || [])
  158. };
  159. // allow custom headers.
  160. if (typeof options.header == 'object') {
  161. populate(headers, options.header);
  162. }
  163. var header;
  164. for (var prop in headers) {
  165. if (!headers.hasOwnProperty(prop)) continue;
  166. header = headers[prop];
  167. // skip nullish headers.
  168. if (header == null) {
  169. continue;
  170. }
  171. // convert all headers to arrays.
  172. if (!Array.isArray(header)) {
  173. header = [header];
  174. }
  175. // add non-empty headers.
  176. if (header.length) {
  177. contents += prop + ': ' + header.join('; ') + FormData.LINE_BREAK;
  178. }
  179. }
  180. return '--' + this.getBoundary() + FormData.LINE_BREAK + contents + FormData.LINE_BREAK;
  181. };
  182. FormData.prototype._getContentDisposition = function(value, options) {
  183. var filename
  184. , contentDisposition
  185. ;
  186. if (typeof options.filepath === 'string') {
  187. // custom filepath for relative paths
  188. filename = path.normalize(options.filepath).replace(/\\/g, '/');
  189. } else if (options.filename || value.name || value.path) {
  190. // custom filename take precedence
  191. // formidable and the browser add a name property
  192. // fs- and request- streams have path property
  193. filename = path.basename(options.filename || value.name || value.path);
  194. } else if (value.readable && value.hasOwnProperty('httpVersion')) {
  195. // or try http response
  196. filename = path.basename(value.client._httpMessage.path || '');
  197. }
  198. if (filename) {
  199. contentDisposition = 'filename="' + filename + '"';
  200. }
  201. return contentDisposition;
  202. };
  203. FormData.prototype._getContentType = function(value, options) {
  204. // use custom content-type above all
  205. var contentType = options.contentType;
  206. // or try `name` from formidable, browser
  207. if (!contentType && value.name) {
  208. contentType = mime.lookup(value.name);
  209. }
  210. // or try `path` from fs-, request- streams
  211. if (!contentType && value.path) {
  212. contentType = mime.lookup(value.path);
  213. }
  214. // or if it's http-reponse
  215. if (!contentType && value.readable && value.hasOwnProperty('httpVersion')) {
  216. contentType = value.headers['content-type'];
  217. }
  218. // or guess it from the filepath or filename
  219. if (!contentType && (options.filepath || options.filename)) {
  220. contentType = mime.lookup(options.filepath || options.filename);
  221. }
  222. // fallback to the default content type if `value` is not simple value
  223. if (!contentType && typeof value == 'object') {
  224. contentType = FormData.DEFAULT_CONTENT_TYPE;
  225. }
  226. return contentType;
  227. };
  228. FormData.prototype._multiPartFooter = function() {
  229. return function(next) {
  230. var footer = FormData.LINE_BREAK;
  231. var lastPart = (this._streams.length === 0);
  232. if (lastPart) {
  233. footer += this._lastBoundary();
  234. }
  235. next(footer);
  236. }.bind(this);
  237. };
  238. FormData.prototype._lastBoundary = function() {
  239. return '--' + this.getBoundary() + '--' + FormData.LINE_BREAK;
  240. };
  241. FormData.prototype.getHeaders = function(userHeaders) {
  242. var header;
  243. var formHeaders = {
  244. 'content-type': 'multipart/form-data; boundary=' + this.getBoundary()
  245. };
  246. for (header in userHeaders) {
  247. if (userHeaders.hasOwnProperty(header)) {
  248. formHeaders[header.toLowerCase()] = userHeaders[header];
  249. }
  250. }
  251. return formHeaders;
  252. };
  253. FormData.prototype.setBoundary = function(boundary) {
  254. this._boundary = boundary;
  255. };
  256. FormData.prototype.getBoundary = function() {
  257. if (!this._boundary) {
  258. this._generateBoundary();
  259. }
  260. return this._boundary;
  261. };
  262. FormData.prototype.getBuffer = function() {
  263. var dataBuffer = new Buffer.alloc( 0 );
  264. var boundary = this.getBoundary();
  265. // Create the form content. Add Line breaks to the end of data.
  266. for (var i = 0, len = this._streams.length; i < len; i++) {
  267. if (typeof this._streams[i] !== 'function') {
  268. // Add content to the buffer.
  269. if(Buffer.isBuffer(this._streams[i])) {
  270. dataBuffer = Buffer.concat( [dataBuffer, this._streams[i]]);
  271. }else {
  272. dataBuffer = Buffer.concat( [dataBuffer, Buffer.from(this._streams[i])]);
  273. }
  274. // Add break after content.
  275. if (typeof this._streams[i] !== 'string' || this._streams[i].substring( 2, boundary.length + 2 ) !== boundary) {
  276. dataBuffer = Buffer.concat( [dataBuffer, Buffer.from(FormData.LINE_BREAK)] );
  277. }
  278. }
  279. }
  280. // Add the footer and return the Buffer object.
  281. return Buffer.concat( [dataBuffer, Buffer.from(this._lastBoundary())] );
  282. };
  283. FormData.prototype._generateBoundary = function() {
  284. // This generates a 50 character boundary similar to those used by Firefox.
  285. // They are optimized for boyer-moore parsing.
  286. var boundary = '--------------------------';
  287. for (var i = 0; i < 24; i++) {
  288. boundary += Math.floor(Math.random() * 10).toString(16);
  289. }
  290. this._boundary = boundary;
  291. };
  292. // Note: getLengthSync DOESN'T calculate streams length
  293. // As workaround one can calculate file size manually
  294. // and add it as knownLength option
  295. FormData.prototype.getLengthSync = function() {
  296. var knownLength = this._overheadLength + this._valueLength;
  297. // Don't get confused, there are 3 "internal" streams for each keyval pair
  298. // so it basically checks if there is any value added to the form
  299. if (this._streams.length) {
  300. knownLength += this._lastBoundary().length;
  301. }
  302. // https://github.com/form-data/form-data/issues/40
  303. if (!this.hasKnownLength()) {
  304. // Some async length retrievers are present
  305. // therefore synchronous length calculation is false.
  306. // Please use getLength(callback) to get proper length
  307. this._error(new Error('Cannot calculate proper length in synchronous way.'));
  308. }
  309. return knownLength;
  310. };
  311. // Public API to check if length of added values is known
  312. // https://github.com/form-data/form-data/issues/196
  313. // https://github.com/form-data/form-data/issues/262
  314. FormData.prototype.hasKnownLength = function() {
  315. var hasKnownLength = true;
  316. if (this._valuesToMeasure.length) {
  317. hasKnownLength = false;
  318. }
  319. return hasKnownLength;
  320. };
  321. FormData.prototype.getLength = function(cb) {
  322. var knownLength = this._overheadLength + this._valueLength;
  323. if (this._streams.length) {
  324. knownLength += this._lastBoundary().length;
  325. }
  326. if (!this._valuesToMeasure.length) {
  327. process.nextTick(cb.bind(this, null, knownLength));
  328. return;
  329. }
  330. asynckit.parallel(this._valuesToMeasure, this._lengthRetriever, function(err, values) {
  331. if (err) {
  332. cb(err);
  333. return;
  334. }
  335. values.forEach(function(length) {
  336. knownLength += length;
  337. });
  338. cb(null, knownLength);
  339. });
  340. };
  341. FormData.prototype.submit = function(params, cb) {
  342. var request
  343. , options
  344. , defaults = {method: 'post'}
  345. ;
  346. // parse provided url if it's string
  347. // or treat it as options object
  348. if (typeof params == 'string') {
  349. params = parseUrl(params);
  350. options = populate({
  351. port: params.port,
  352. path: params.pathname,
  353. host: params.hostname,
  354. protocol: params.protocol
  355. }, defaults);
  356. // use custom params
  357. } else {
  358. options = populate(params, defaults);
  359. // if no port provided use default one
  360. if (!options.port) {
  361. options.port = options.protocol == 'https:' ? 443 : 80;
  362. }
  363. }
  364. // put that good code in getHeaders to some use
  365. options.headers = this.getHeaders(params.headers);
  366. // https if specified, fallback to http in any other case
  367. if (options.protocol == 'https:') {
  368. request = https.request(options);
  369. } else {
  370. request = http.request(options);
  371. }
  372. // get content length and fire away
  373. this.getLength(function(err, length) {
  374. if (err && err !== 'Unknown stream') {
  375. this._error(err);
  376. return;
  377. }
  378. // add content length
  379. if (length) {
  380. request.setHeader('Content-Length', length);
  381. }
  382. this.pipe(request);
  383. if (cb) {
  384. var onResponse;
  385. var callback = function (error, responce) {
  386. request.removeListener('error', callback);
  387. request.removeListener('response', onResponse);
  388. return cb.call(this, error, responce);
  389. };
  390. onResponse = callback.bind(this, null);
  391. request.on('error', callback);
  392. request.on('response', onResponse);
  393. }
  394. }.bind(this));
  395. return request;
  396. };
  397. FormData.prototype._error = function(err) {
  398. if (!this.error) {
  399. this.error = err;
  400. this.pause();
  401. this.emit('error', err);
  402. }
  403. };
  404. FormData.prototype.toString = function () {
  405. return '[object FormData]';
  406. };
  407. }, function(modId) {var map = {"./populate.js":1662612701775}; return __REQUIRE__(map[modId], modId); })
  408. __DEFINE__(1662612701775, function(require, module, exports) {
  409. // populates missing values
  410. module.exports = function(dst, src) {
  411. Object.keys(src).forEach(function(prop)
  412. {
  413. dst[prop] = dst[prop] || src[prop];
  414. });
  415. return dst;
  416. };
  417. }, function(modId) { var map = {}; return __REQUIRE__(map[modId], modId); })
  418. return __REQUIRE__(1662612701774);
  419. })()
  420. //miniprogram-npm-outsideDeps=["combined-stream","util","path","http","https","url","fs","stream","mime-types","asynckit"]
  421. //# sourceMappingURL=index.js.map