index.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810
  1. var stream = require('stream');
  2. var util = require('util');
  3. var fs = require('fs');
  4. var crypto = require('crypto');
  5. var path = require('path');
  6. var os = require('os');
  7. var StringDecoder = require('string_decoder').StringDecoder;
  8. var fdSlicer = require('fd-slicer');
  9. var START = 0;
  10. var START_BOUNDARY = 1;
  11. var HEADER_FIELD_START = 2;
  12. var HEADER_FIELD = 3;
  13. var HEADER_VALUE_START = 4;
  14. var HEADER_VALUE = 5;
  15. var HEADER_VALUE_ALMOST_DONE = 6;
  16. var HEADERS_ALMOST_DONE = 7;
  17. var PART_DATA_START = 8;
  18. var PART_DATA = 9;
  19. var PART_END = 10;
  20. var CLOSE_BOUNDARY = 11;
  21. var END = 12;
  22. var LF = 10;
  23. var CR = 13;
  24. var SPACE = 32;
  25. var HYPHEN = 45;
  26. var COLON = 58;
  27. var A = 97;
  28. var Z = 122;
  29. var CONTENT_TYPE_RE = /^multipart\/(?:form-data|related)(?:;|$)/i;
  30. var CONTENT_TYPE_PARAM_RE = /;\s*([^=]+)=(?:"([^"]+)"|([^;]+))/gi;
  31. var FILE_EXT_RE = /(\.[_\-a-zA-Z0-9]{0,16}).*/;
  32. var LAST_BOUNDARY_SUFFIX_LEN = 4; // --\r\n
  33. // replace base64 characters with safe-for-filename characters
  34. var b64Safe = {'/': '_', '+': '-'};
  35. exports.Form = Form;
  36. util.inherits(Form, stream.Writable);
  37. function Form(options) {
  38. var self = this;
  39. stream.Writable.call(self);
  40. options = options || {};
  41. self.error = null;
  42. self.autoFields = !!options.autoFields;
  43. self.autoFiles = !!options.autoFiles;
  44. self.maxFields = options.maxFields || 1000;
  45. self.maxFieldsSize = options.maxFieldsSize || 2 * 1024 * 1024;
  46. self.maxFilesSize = options.maxFilesSize || Infinity;
  47. self.uploadDir = options.uploadDir || os.tmpdir();
  48. self.encoding = options.encoding || 'utf8';
  49. self.bytesReceived = 0;
  50. self.bytesExpected = null;
  51. self.openedFiles = [];
  52. self.totalFieldSize = 0;
  53. self.totalFieldCount = 0;
  54. self.totalFileSize = 0;
  55. self.flushing = 0;
  56. self.backpressure = false;
  57. self.writeCbs = [];
  58. self.emitQueue = [];
  59. self.on('newListener', function(eventName) {
  60. if (eventName === 'file') {
  61. self.autoFiles = true;
  62. } else if (eventName === 'field') {
  63. self.autoFields = true;
  64. }
  65. });
  66. }
  67. Form.prototype.parse = function(req, cb) {
  68. var called = false;
  69. var self = this;
  70. var waitend = true;
  71. if (cb) {
  72. // if the user supplies a callback, this implies autoFields and autoFiles
  73. self.autoFields = true;
  74. self.autoFiles = true;
  75. // wait for request to end before calling cb
  76. var end = function (done) {
  77. if (called) return;
  78. called = true;
  79. // wait for req events to fire
  80. process.nextTick(function() {
  81. if (waitend && req.readable) {
  82. // dump rest of request
  83. req.resume();
  84. req.once('end', done);
  85. return;
  86. }
  87. done();
  88. });
  89. };
  90. var fields = {};
  91. var files = {};
  92. self.on('error', function(err) {
  93. end(function() {
  94. cb(err);
  95. });
  96. });
  97. self.on('field', function(name, value) {
  98. var fieldsArray = fields[name] || (fields[name] = []);
  99. fieldsArray.push(value);
  100. });
  101. self.on('file', function(name, file) {
  102. var filesArray = files[name] || (files[name] = []);
  103. filesArray.push(file);
  104. });
  105. self.on('close', function() {
  106. end(function() {
  107. cb(null, fields, files);
  108. });
  109. });
  110. }
  111. self.handleError = handleError;
  112. self.bytesExpected = getBytesExpected(req.headers);
  113. req.on('end', onReqEnd);
  114. req.on('error', function(err) {
  115. waitend = false;
  116. handleError(err);
  117. });
  118. req.on('aborted', onReqAborted);
  119. var state = req._readableState;
  120. if (req._decoder || (state && (state.encoding || state.decoder))) {
  121. // this is a binary protocol
  122. // if an encoding is set, input is likely corrupted
  123. validationError(new Error('request encoding must not be set'));
  124. return;
  125. }
  126. var contentType = req.headers['content-type'];
  127. if (!contentType) {
  128. validationError(createError(415, 'missing content-type header'));
  129. return;
  130. }
  131. var m = CONTENT_TYPE_RE.exec(contentType);
  132. if (!m) {
  133. validationError(createError(415, 'unsupported content-type'));
  134. return;
  135. }
  136. var boundary;
  137. CONTENT_TYPE_PARAM_RE.lastIndex = m.index + m[0].length - 1;
  138. while ((m = CONTENT_TYPE_PARAM_RE.exec(contentType))) {
  139. if (m[1].toLowerCase() !== 'boundary') continue;
  140. boundary = m[2] || m[3];
  141. break;
  142. }
  143. if (!boundary) {
  144. validationError(createError(400, 'content-type missing boundary'));
  145. return;
  146. }
  147. setUpParser(self, boundary);
  148. req.pipe(self);
  149. function onReqAborted() {
  150. waitend = false;
  151. self.emit('aborted');
  152. handleError(new Error("Request aborted"));
  153. }
  154. function onReqEnd() {
  155. waitend = false;
  156. }
  157. function handleError(err) {
  158. var first = !self.error;
  159. if (first) {
  160. self.error = err;
  161. req.removeListener('aborted', onReqAborted);
  162. req.removeListener('end', onReqEnd);
  163. if (self.destStream) {
  164. errorEventQueue(self, self.destStream, err);
  165. }
  166. }
  167. cleanupOpenFiles(self);
  168. if (first) {
  169. self.emit('error', err);
  170. }
  171. }
  172. function validationError(err) {
  173. // handle error on next tick for event listeners to attach
  174. process.nextTick(handleError.bind(null, err))
  175. }
  176. };
  177. Form.prototype._write = function(buffer, encoding, cb) {
  178. if (this.error) return;
  179. var self = this;
  180. var i = 0;
  181. var len = buffer.length;
  182. var prevIndex = self.index;
  183. var index = self.index;
  184. var state = self.state;
  185. var lookbehind = self.lookbehind;
  186. var boundary = self.boundary;
  187. var boundaryChars = self.boundaryChars;
  188. var boundaryLength = self.boundary.length;
  189. var boundaryEnd = boundaryLength - 1;
  190. var bufferLength = buffer.length;
  191. var c;
  192. var cl;
  193. for (i = 0; i < len; i++) {
  194. c = buffer[i];
  195. switch (state) {
  196. case START:
  197. index = 0;
  198. state = START_BOUNDARY;
  199. /* falls through */
  200. case START_BOUNDARY:
  201. if (index === boundaryLength - 2 && c === HYPHEN) {
  202. index = 1;
  203. state = CLOSE_BOUNDARY;
  204. break;
  205. } else if (index === boundaryLength - 2) {
  206. if (c !== CR) return self.handleError(createError(400, 'Expected CR Received ' + c));
  207. index++;
  208. break;
  209. } else if (index === boundaryLength - 1) {
  210. if (c !== LF) return self.handleError(createError(400, 'Expected LF Received ' + c));
  211. index = 0;
  212. self.onParsePartBegin();
  213. state = HEADER_FIELD_START;
  214. break;
  215. }
  216. if (c !== boundary[index+2]) index = -2;
  217. if (c === boundary[index+2]) index++;
  218. break;
  219. case HEADER_FIELD_START:
  220. state = HEADER_FIELD;
  221. self.headerFieldMark = i;
  222. index = 0;
  223. /* falls through */
  224. case HEADER_FIELD:
  225. if (c === CR) {
  226. self.headerFieldMark = null;
  227. state = HEADERS_ALMOST_DONE;
  228. break;
  229. }
  230. index++;
  231. if (c === HYPHEN) break;
  232. if (c === COLON) {
  233. if (index === 1) {
  234. // empty header field
  235. self.handleError(createError(400, 'Empty header field'));
  236. return;
  237. }
  238. self.onParseHeaderField(buffer.slice(self.headerFieldMark, i));
  239. self.headerFieldMark = null;
  240. state = HEADER_VALUE_START;
  241. break;
  242. }
  243. cl = lower(c);
  244. if (cl < A || cl > Z) {
  245. self.handleError(createError(400, 'Expected alphabetic character, received ' + c));
  246. return;
  247. }
  248. break;
  249. case HEADER_VALUE_START:
  250. if (c === SPACE) break;
  251. self.headerValueMark = i;
  252. state = HEADER_VALUE;
  253. /* falls through */
  254. case HEADER_VALUE:
  255. if (c === CR) {
  256. self.onParseHeaderValue(buffer.slice(self.headerValueMark, i));
  257. self.headerValueMark = null;
  258. self.onParseHeaderEnd();
  259. state = HEADER_VALUE_ALMOST_DONE;
  260. }
  261. break;
  262. case HEADER_VALUE_ALMOST_DONE:
  263. if (c !== LF) return self.handleError(createError(400, 'Expected LF Received ' + c));
  264. state = HEADER_FIELD_START;
  265. break;
  266. case HEADERS_ALMOST_DONE:
  267. if (c !== LF) return self.handleError(createError(400, 'Expected LF Received ' + c));
  268. var err = self.onParseHeadersEnd(i + 1);
  269. if (err) return self.handleError(err);
  270. state = PART_DATA_START;
  271. break;
  272. case PART_DATA_START:
  273. state = PART_DATA;
  274. self.partDataMark = i;
  275. /* falls through */
  276. case PART_DATA:
  277. prevIndex = index;
  278. if (index === 0) {
  279. // boyer-moore derrived algorithm to safely skip non-boundary data
  280. i += boundaryEnd;
  281. while (i < bufferLength && !(buffer[i] in boundaryChars)) {
  282. i += boundaryLength;
  283. }
  284. i -= boundaryEnd;
  285. c = buffer[i];
  286. }
  287. if (index < boundaryLength) {
  288. if (boundary[index] === c) {
  289. if (index === 0) {
  290. self.onParsePartData(buffer.slice(self.partDataMark, i));
  291. self.partDataMark = null;
  292. }
  293. index++;
  294. } else {
  295. index = 0;
  296. }
  297. } else if (index === boundaryLength) {
  298. index++;
  299. if (c === CR) {
  300. // CR = part boundary
  301. self.partBoundaryFlag = true;
  302. } else if (c === HYPHEN) {
  303. index = 1;
  304. state = CLOSE_BOUNDARY;
  305. break;
  306. } else {
  307. index = 0;
  308. }
  309. } else if (index - 1 === boundaryLength) {
  310. if (self.partBoundaryFlag) {
  311. index = 0;
  312. if (c === LF) {
  313. self.partBoundaryFlag = false;
  314. self.onParsePartEnd();
  315. self.onParsePartBegin();
  316. state = HEADER_FIELD_START;
  317. break;
  318. }
  319. } else {
  320. index = 0;
  321. }
  322. }
  323. if (index > 0) {
  324. // when matching a possible boundary, keep a lookbehind reference
  325. // in case it turns out to be a false lead
  326. lookbehind[index-1] = c;
  327. } else if (prevIndex > 0) {
  328. // if our boundary turned out to be rubbish, the captured lookbehind
  329. // belongs to partData
  330. self.onParsePartData(lookbehind.slice(0, prevIndex));
  331. prevIndex = 0;
  332. self.partDataMark = i;
  333. // reconsider the current character even so it interrupted the sequence
  334. // it could be the beginning of a new sequence
  335. i--;
  336. }
  337. break;
  338. case CLOSE_BOUNDARY:
  339. if (c !== HYPHEN) return self.handleError(createError(400, 'Expected HYPHEN Received ' + c));
  340. if (index === 1) {
  341. self.onParsePartEnd();
  342. state = END;
  343. } else if (index > 1) {
  344. return self.handleError(new Error("Parser has invalid state."));
  345. }
  346. index++;
  347. break;
  348. case END:
  349. break;
  350. default:
  351. self.handleError(new Error("Parser has invalid state."));
  352. return;
  353. }
  354. }
  355. if (self.headerFieldMark != null) {
  356. self.onParseHeaderField(buffer.slice(self.headerFieldMark));
  357. self.headerFieldMark = 0;
  358. }
  359. if (self.headerValueMark != null) {
  360. self.onParseHeaderValue(buffer.slice(self.headerValueMark));
  361. self.headerValueMark = 0;
  362. }
  363. if (self.partDataMark != null) {
  364. self.onParsePartData(buffer.slice(self.partDataMark));
  365. self.partDataMark = 0;
  366. }
  367. self.index = index;
  368. self.state = state;
  369. self.bytesReceived += buffer.length;
  370. self.emit('progress', self.bytesReceived, self.bytesExpected);
  371. if (self.backpressure) {
  372. self.writeCbs.push(cb);
  373. } else {
  374. cb();
  375. }
  376. };
  377. Form.prototype.onParsePartBegin = function() {
  378. clearPartVars(this);
  379. }
  380. Form.prototype.onParseHeaderField = function(b) {
  381. this.headerField += this.headerFieldDecoder.write(b);
  382. }
  383. Form.prototype.onParseHeaderValue = function(b) {
  384. this.headerValue += this.headerValueDecoder.write(b);
  385. }
  386. Form.prototype.onParseHeaderEnd = function() {
  387. this.headerField = this.headerField.toLowerCase();
  388. this.partHeaders[this.headerField] = this.headerValue;
  389. var m;
  390. if (this.headerField === 'content-disposition') {
  391. if (m = this.headerValue.match(/\bname="([^"]+)"/i)) {
  392. this.partName = m[1];
  393. }
  394. this.partFilename = parseFilename(this.headerValue);
  395. } else if (this.headerField === 'content-transfer-encoding') {
  396. this.partTransferEncoding = this.headerValue.toLowerCase();
  397. }
  398. this.headerFieldDecoder = new StringDecoder(this.encoding);
  399. this.headerField = '';
  400. this.headerValueDecoder = new StringDecoder(this.encoding);
  401. this.headerValue = '';
  402. }
  403. Form.prototype.onParsePartData = function(b) {
  404. if (this.partTransferEncoding === 'base64') {
  405. this.backpressure = ! this.destStream.write(b.toString('ascii'), 'base64');
  406. } else {
  407. this.backpressure = ! this.destStream.write(b);
  408. }
  409. }
  410. Form.prototype.onParsePartEnd = function() {
  411. if (this.destStream) {
  412. flushWriteCbs(this);
  413. var s = this.destStream;
  414. process.nextTick(function() {
  415. s.end();
  416. });
  417. }
  418. clearPartVars(this);
  419. }
  420. Form.prototype.onParseHeadersEnd = function(offset) {
  421. var self = this;
  422. switch(self.partTransferEncoding){
  423. case 'binary':
  424. case '7bit':
  425. case '8bit':
  426. self.partTransferEncoding = 'binary';
  427. break;
  428. case 'base64': break;
  429. default:
  430. return createError(400, 'unknown transfer-encoding: ' + self.partTransferEncoding);
  431. }
  432. self.totalFieldCount += 1;
  433. if (self.totalFieldCount > self.maxFields) {
  434. return createError(413, 'maxFields ' + self.maxFields + ' exceeded.');
  435. }
  436. self.destStream = new stream.PassThrough();
  437. self.destStream.on('drain', function() {
  438. flushWriteCbs(self);
  439. });
  440. self.destStream.headers = self.partHeaders;
  441. self.destStream.name = self.partName;
  442. self.destStream.filename = self.partFilename;
  443. self.destStream.byteOffset = self.bytesReceived + offset;
  444. var partContentLength = self.destStream.headers['content-length'];
  445. self.destStream.byteCount = partContentLength ? parseInt(partContentLength, 10) :
  446. self.bytesExpected ? (self.bytesExpected - self.destStream.byteOffset -
  447. self.boundary.length - LAST_BOUNDARY_SUFFIX_LEN) :
  448. undefined;
  449. if (self.destStream.filename == null && self.autoFields) {
  450. handleField(self, self.destStream);
  451. } else if (self.destStream.filename != null && self.autoFiles) {
  452. handleFile(self, self.destStream);
  453. } else {
  454. handlePart(self, self.destStream);
  455. }
  456. }
  457. function flushWriteCbs(self) {
  458. self.writeCbs.forEach(function(cb) {
  459. process.nextTick(cb);
  460. });
  461. self.writeCbs = [];
  462. self.backpressure = false;
  463. }
  464. function getBytesExpected(headers) {
  465. var contentLength = headers['content-length'];
  466. if (contentLength) {
  467. return parseInt(contentLength, 10);
  468. } else if (headers['transfer-encoding'] == null) {
  469. return 0;
  470. } else {
  471. return null;
  472. }
  473. }
  474. function beginFlush(self) {
  475. self.flushing += 1;
  476. }
  477. function endFlush(self) {
  478. self.flushing -= 1;
  479. if (self.flushing < 0) {
  480. // if this happens this is a critical bug in multiparty and this stack trace
  481. // will help us figure it out.
  482. self.handleError(new Error("unexpected endFlush"));
  483. return;
  484. }
  485. maybeClose(self);
  486. }
  487. function maybeClose(self) {
  488. if (self.flushing > 0 || self.error) return;
  489. // go through the emit queue in case any field, file, or part events are
  490. // waiting to be emitted
  491. holdEmitQueue(self)(function() {
  492. // nextTick because the user is listening to part 'end' events and we are
  493. // using part 'end' events to decide when to emit 'close'. we add our 'end'
  494. // handler before the user gets a chance to add theirs. So we make sure
  495. // their 'end' event fires before we emit the 'close' event.
  496. // this is covered by test/standalone/test-issue-36
  497. process.nextTick(function() {
  498. self.emit('close');
  499. });
  500. });
  501. }
  502. function cleanupOpenFiles(self) {
  503. self.openedFiles.forEach(function(internalFile) {
  504. // since fd slicer autoClose is true, destroying the only write stream
  505. // is guaranteed by the API to close the fd
  506. internalFile.ws.destroy();
  507. fs.unlink(internalFile.publicFile.path, function(err) {
  508. if (err) self.handleError(err);
  509. });
  510. });
  511. self.openedFiles = [];
  512. }
  513. function holdEmitQueue(self, eventEmitter) {
  514. var item = {cb: null, ee: eventEmitter, err: null};
  515. self.emitQueue.push(item);
  516. return function(cb) {
  517. item.cb = cb;
  518. flushEmitQueue(self);
  519. };
  520. }
  521. function errorEventQueue(self, eventEmitter, err) {
  522. var items = self.emitQueue.filter(function (item) {
  523. return item.ee === eventEmitter;
  524. });
  525. if (items.length === 0) {
  526. eventEmitter.emit('error', err);
  527. return;
  528. }
  529. items.forEach(function (item) {
  530. item.err = err;
  531. });
  532. }
  533. function flushEmitQueue(self) {
  534. while (self.emitQueue.length > 0 && self.emitQueue[0].cb) {
  535. var item = self.emitQueue.shift();
  536. // invoke the callback
  537. item.cb();
  538. if (item.err) {
  539. // emit the delayed error
  540. item.ee.emit('error', item.err);
  541. }
  542. }
  543. }
  544. function handlePart(self, partStream) {
  545. beginFlush(self);
  546. var emitAndReleaseHold = holdEmitQueue(self, partStream);
  547. partStream.on('end', function() {
  548. endFlush(self);
  549. });
  550. emitAndReleaseHold(function() {
  551. self.emit('part', partStream);
  552. });
  553. }
  554. function handleFile(self, fileStream) {
  555. if (self.error) return;
  556. var publicFile = {
  557. fieldName: fileStream.name,
  558. originalFilename: fileStream.filename,
  559. path: uploadPath(self.uploadDir, fileStream.filename),
  560. headers: fileStream.headers,
  561. size: 0,
  562. };
  563. var internalFile = {
  564. publicFile: publicFile,
  565. ws: null,
  566. };
  567. beginFlush(self); // flush to write stream
  568. var emitAndReleaseHold = holdEmitQueue(self, fileStream);
  569. fileStream.on('error', function(err) {
  570. self.handleError(err);
  571. });
  572. fs.open(publicFile.path, 'wx', function(err, fd) {
  573. if (err) return self.handleError(err);
  574. var slicer = fdSlicer.createFromFd(fd, {autoClose: true});
  575. // end option here guarantees that no more than that amount will be written
  576. // or else an error will be emitted
  577. internalFile.ws = slicer.createWriteStream({end: self.maxFilesSize - self.totalFileSize});
  578. // if an error ocurred while we were waiting for fs.open we handle that
  579. // cleanup now
  580. self.openedFiles.push(internalFile);
  581. if (self.error) return cleanupOpenFiles(self);
  582. var prevByteCount = 0;
  583. internalFile.ws.on('error', function(err) {
  584. if (err.code === 'ETOOBIG') {
  585. err = createError(413, err.message);
  586. err.code = 'ETOOBIG';
  587. }
  588. self.handleError(err);
  589. });
  590. internalFile.ws.on('progress', function() {
  591. publicFile.size = internalFile.ws.bytesWritten;
  592. var delta = publicFile.size - prevByteCount;
  593. self.totalFileSize += delta;
  594. prevByteCount = publicFile.size;
  595. });
  596. slicer.on('close', function() {
  597. if (self.error) return;
  598. emitAndReleaseHold(function() {
  599. self.emit('file', fileStream.name, publicFile);
  600. });
  601. endFlush(self);
  602. });
  603. fileStream.pipe(internalFile.ws);
  604. });
  605. }
  606. function handleField(self, fieldStream) {
  607. var value = '';
  608. var decoder = new StringDecoder(self.encoding);
  609. beginFlush(self);
  610. var emitAndReleaseHold = holdEmitQueue(self, fieldStream);
  611. fieldStream.on('error', function(err) {
  612. self.handleError(err);
  613. });
  614. fieldStream.on('readable', function() {
  615. var buffer = fieldStream.read();
  616. if (!buffer) return;
  617. self.totalFieldSize += buffer.length;
  618. if (self.totalFieldSize > self.maxFieldsSize) {
  619. self.handleError(createError(413, 'maxFieldsSize ' + self.maxFieldsSize + ' exceeded'));
  620. return;
  621. }
  622. value += decoder.write(buffer);
  623. });
  624. fieldStream.on('end', function() {
  625. emitAndReleaseHold(function() {
  626. self.emit('field', fieldStream.name, value);
  627. });
  628. endFlush(self);
  629. });
  630. }
  631. function clearPartVars(self) {
  632. self.partHeaders = {};
  633. self.partName = null;
  634. self.partFilename = null;
  635. self.partTransferEncoding = 'binary';
  636. self.destStream = null;
  637. self.headerFieldDecoder = new StringDecoder(self.encoding);
  638. self.headerField = "";
  639. self.headerValueDecoder = new StringDecoder(self.encoding);
  640. self.headerValue = "";
  641. }
  642. function setUpParser(self, boundary) {
  643. self.boundary = new Buffer(boundary.length + 4);
  644. self.boundary.write('\r\n--', 0, boundary.length + 4, 'ascii');
  645. self.boundary.write(boundary, 4, boundary.length, 'ascii');
  646. self.lookbehind = new Buffer(self.boundary.length + 8);
  647. self.state = START;
  648. self.boundaryChars = {};
  649. for (var i = 0; i < self.boundary.length; i++) {
  650. self.boundaryChars[self.boundary[i]] = true;
  651. }
  652. self.index = null;
  653. self.partBoundaryFlag = false;
  654. beginFlush(self);
  655. self.on('finish', function() {
  656. if (self.state !== END) {
  657. self.handleError(createError(400, 'stream ended unexpectedly'));
  658. }
  659. endFlush(self);
  660. });
  661. }
  662. function uploadPath(baseDir, filename) {
  663. var ext = path.extname(filename).replace(FILE_EXT_RE, '$1');
  664. var name = randoString(18) + ext;
  665. return path.join(baseDir, name);
  666. }
  667. function randoString(size) {
  668. return rando(size).toString('base64').replace(/[\/\+]/g, function(x) {
  669. return b64Safe[x];
  670. });
  671. }
  672. function rando(size) {
  673. try {
  674. return crypto.randomBytes(size);
  675. } catch (err) {
  676. return crypto.pseudoRandomBytes(size);
  677. }
  678. }
  679. function parseFilename(headerValue) {
  680. var m = headerValue.match(/\bfilename="(.*?)"($|; )/i);
  681. if (!m) {
  682. m = headerValue.match(/\bfilename\*=utf-8\'\'(.*?)($|; )/i);
  683. if (m) {
  684. m[1] = decodeURI(m[1]);
  685. }
  686. else {
  687. return;
  688. }
  689. }
  690. var filename = m[1];
  691. filename = filename.replace(/%22|\\"/g, '"');
  692. filename = filename.replace(/&#([\d]{4});/g, function(m, code) {
  693. return String.fromCharCode(code);
  694. });
  695. return filename.substr(filename.lastIndexOf('\\') + 1);
  696. }
  697. function lower(c) {
  698. return c | 0x20;
  699. }
  700. function createError(status, message) {
  701. var error = new Error(message);
  702. Error.captureStackTrace(error, createError);
  703. error.status = status;
  704. error.statusCode = status;
  705. return error;
  706. }