You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					485 lines
				
				9.7 KiB
			
		
		
			
		
	
	
					485 lines
				
				9.7 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Parted (https://github.com/chjj/parted)
							 | 
						||
| 
								 | 
							
								 * A streaming multipart state parser.
							 | 
						||
| 
								 | 
							
								 * Copyright (c) 2011, Christopher Jeffrey. (MIT Licensed)
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var fs = require('fs')
							 | 
						||
| 
								 | 
							
								  , path = require('path')
							 | 
						||
| 
								 | 
							
								  , EventEmitter = require('events').EventEmitter
							 | 
						||
| 
								 | 
							
								  , StringDecoder = require('string_decoder').StringDecoder
							 | 
						||
| 
								 | 
							
								  , set = require('qs').set
							 | 
						||
| 
								 | 
							
								  , each = Array.prototype.forEach;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Character Constants
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var DASH = '-'.charCodeAt(0)
							 | 
						||
| 
								 | 
							
								  , CR = '\r'.charCodeAt(0)
							 | 
						||
| 
								 | 
							
								  , LF = '\n'.charCodeAt(0)
							 | 
						||
| 
								 | 
							
								  , COLON = ':'.charCodeAt(0)
							 | 
						||
| 
								 | 
							
								  , SPACE = ' '.charCodeAt(0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Parser
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var Parser = function(type, options) {
							 | 
						||
| 
								 | 
							
								  if (!(this instanceof Parser)) {
							 | 
						||
| 
								 | 
							
								    return new Parser(type, options);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  EventEmitter.call(this);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this.writable = true;
							 | 
						||
| 
								 | 
							
								  this.readable = true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this.options = options || {};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var key = grab(type, 'boundary');
							 | 
						||
| 
								 | 
							
								  if (!key) {
							 | 
						||
| 
								 | 
							
								    return this._error('No boundary key found.');
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this.key = new Buffer('\r\n--' + key);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this._key = {};
							 | 
						||
| 
								 | 
							
								  each.call(this.key, function(ch) {
							 | 
						||
| 
								 | 
							
								    this._key[ch] = true;
							 | 
						||
| 
								 | 
							
								  }, this);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this.state = 'start';
							 | 
						||
| 
								 | 
							
								  this.pending = 0;
							 | 
						||
| 
								 | 
							
								  this.written = 0;
							 | 
						||
| 
								 | 
							
								  this.writtenDisk = 0;
							 | 
						||
| 
								 | 
							
								  this.buff = new Buffer(200);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this.preamble = true;
							 | 
						||
| 
								 | 
							
								  this.epilogue = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this._reset();
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Parser.prototype.__proto__ = EventEmitter.prototype;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Parsing
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Parser.prototype.write = function(data) {
							 | 
						||
| 
								 | 
							
								  if (!this.writable
							 | 
						||
| 
								 | 
							
								      || this.epilogue) return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  try {
							 | 
						||
| 
								 | 
							
								    this._parse(data);
							 | 
						||
| 
								 | 
							
								  } catch (e) {
							 | 
						||
| 
								 | 
							
								    this._error(e);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return true;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Parser.prototype.end = function(data) {
							 | 
						||
| 
								 | 
							
								  if (!this.writable) return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (data) this.write(data);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!this.epilogue) {
							 | 
						||
| 
								 | 
							
								    return this._error('Message underflow.');
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return true;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Parser.prototype._parse = function(data) {
							 | 
						||
| 
								 | 
							
								  var i = 0
							 | 
						||
| 
								 | 
							
								    , len = data.length
							 | 
						||
| 
								 | 
							
								    , buff = this.buff
							 | 
						||
| 
								 | 
							
								    , key = this.key
							 | 
						||
| 
								 | 
							
								    , ch
							 | 
						||
| 
								 | 
							
								    , val
							 | 
						||
| 
								 | 
							
								    , j;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (; i < len; i++) {
							 | 
						||
| 
								 | 
							
								    if (this.pos >= 200) {
							 | 
						||
| 
								 | 
							
								      return this._error('Potential buffer overflow.');
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ch = data[i];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    switch (this.state) {
							 | 
						||
| 
								 | 
							
								      case 'start':
							 | 
						||
| 
								 | 
							
								        switch (ch) {
							 | 
						||
| 
								 | 
							
								          case DASH:
							 | 
						||
| 
								 | 
							
								            this.pos = 3;
							 | 
						||
| 
								 | 
							
								            this.state = 'key';
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								          default:
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								      case 'key':
							 | 
						||
| 
								 | 
							
								        if (this.pos === key.length) {
							 | 
						||
| 
								 | 
							
								          this.state = 'key_end';
							 | 
						||
| 
								 | 
							
								          i--;
							 | 
						||
| 
								 | 
							
								        } else if (ch !== key[this.pos]) {
							 | 
						||
| 
								 | 
							
								          if (this.preamble) {
							 | 
						||
| 
								 | 
							
								            this.state = 'start';
							 | 
						||
| 
								 | 
							
								            i--;
							 | 
						||
| 
								 | 
							
								          } else {
							 | 
						||
| 
								 | 
							
								            this.state = 'body';
							 | 
						||
| 
								 | 
							
								            val = this.pos - i;
							 | 
						||
| 
								 | 
							
								            if (val > 0) {
							 | 
						||
| 
								 | 
							
								              this._write(key.slice(0, val));
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            i--;
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								          this.pos++;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								      case 'key_end':
							 | 
						||
| 
								 | 
							
								        switch (ch) {
							 | 
						||
| 
								 | 
							
								          case CR:
							 | 
						||
| 
								 | 
							
								            this.state = 'key_line_end';
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								          case DASH:
							 | 
						||
| 
								 | 
							
								            this.state = 'key_dash_end';
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								          default:
							 | 
						||
| 
								 | 
							
								            return this._error('Expected CR or DASH.');
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								      case 'key_line_end':
							 | 
						||
| 
								 | 
							
								        switch (ch) {
							 | 
						||
| 
								 | 
							
								          case LF:
							 | 
						||
| 
								 | 
							
								            if (this.preamble) {
							 | 
						||
| 
								 | 
							
								              this.preamble = false;
							 | 
						||
| 
								 | 
							
								            } else {
							 | 
						||
| 
								 | 
							
								              this._finish();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            this.state = 'header_name';
							 | 
						||
| 
								 | 
							
								            this.pos = 0;
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								          default:
							 | 
						||
| 
								 | 
							
								            return this._error('Expected CR.');
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								      case 'key_dash_end':
							 | 
						||
| 
								 | 
							
								        switch (ch) {
							 | 
						||
| 
								 | 
							
								          case DASH:
							 | 
						||
| 
								 | 
							
								            this.epilogue = true;
							 | 
						||
| 
								 | 
							
								            this._finish();
							 | 
						||
| 
								 | 
							
								            return;
							 | 
						||
| 
								 | 
							
								          default:
							 | 
						||
| 
								 | 
							
								            return this._error('Expected DASH.');
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								      case 'header_name':
							 | 
						||
| 
								 | 
							
								        switch (ch) {
							 | 
						||
| 
								 | 
							
								          case COLON:
							 | 
						||
| 
								 | 
							
								            this.header = buff.toString('ascii', 0, this.pos);
							 | 
						||
| 
								 | 
							
								            this.pos = 0;
							 | 
						||
| 
								 | 
							
								            this.state = 'header_val';
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								          default:
							 | 
						||
| 
								 | 
							
								            buff[this.pos++] = ch | 32;
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								      case 'header_val':
							 | 
						||
| 
								 | 
							
								        switch (ch) {
							 | 
						||
| 
								 | 
							
								          case CR:
							 | 
						||
| 
								 | 
							
								            this.state = 'header_val_end';
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								          case SPACE:
							 | 
						||
| 
								 | 
							
								            if (this.pos === 0) {
							 | 
						||
| 
								 | 
							
								              break;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            ; // FALL-THROUGH
							 | 
						||
| 
								 | 
							
								          default:
							 | 
						||
| 
								 | 
							
								            buff[this.pos++] = ch;
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								      case 'header_val_end':
							 | 
						||
| 
								 | 
							
								        switch (ch) {
							 | 
						||
| 
								 | 
							
								          case LF:
							 | 
						||
| 
								 | 
							
								            val = buff.toString('ascii', 0, this.pos);
							 | 
						||
| 
								 | 
							
								            this._header(this.header, val);
							 | 
						||
| 
								 | 
							
								            this.pos = 0;
							 | 
						||
| 
								 | 
							
								            this.state = 'header_end';
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								          default:
							 | 
						||
| 
								 | 
							
								            return this._error('Expected LF.');
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								      case 'header_end':
							 | 
						||
| 
								 | 
							
								        switch (ch) {
							 | 
						||
| 
								 | 
							
								          case CR:
							 | 
						||
| 
								 | 
							
								            this.state = 'head_end';
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								          default:
							 | 
						||
| 
								 | 
							
								            this.state = 'header_name';
							 | 
						||
| 
								 | 
							
								            i--;
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								      case 'head_end':
							 | 
						||
| 
								 | 
							
								        switch (ch) {
							 | 
						||
| 
								 | 
							
								          case LF:
							 | 
						||
| 
								 | 
							
								            this.state = 'body';
							 | 
						||
| 
								 | 
							
								            i++;
							 | 
						||
| 
								 | 
							
								            if (i >= len) return;
							 | 
						||
| 
								 | 
							
								            data = data.slice(i);
							 | 
						||
| 
								 | 
							
								            i = -1;
							 | 
						||
| 
								 | 
							
								            len = data.length;
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								          default:
							 | 
						||
| 
								 | 
							
								            return this._error('Expected LF.');
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								      case 'body':
							 | 
						||
| 
								 | 
							
								        switch (ch) {
							 | 
						||
| 
								 | 
							
								          case CR:
							 | 
						||
| 
								 | 
							
								            if (i > 0) {
							 | 
						||
| 
								 | 
							
								              this._write(data.slice(0, i));
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            this.pos = 1;
							 | 
						||
| 
								 | 
							
								            this.state = 'key';
							 | 
						||
| 
								 | 
							
								            data = data.slice(i);
							 | 
						||
| 
								 | 
							
								            i = 0;
							 | 
						||
| 
								 | 
							
								            len = data.length;
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								          default:
							 | 
						||
| 
								 | 
							
								            // boyer-moore-like algorithm
							 | 
						||
| 
								 | 
							
								            // at felixge's suggestion
							 | 
						||
| 
								 | 
							
								            while ((j = i + key.length - 1) < len) {
							 | 
						||
| 
								 | 
							
								              if (this._key[data[j]]) break;
							 | 
						||
| 
								 | 
							
								              i = j;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (this.state === 'body') {
							 | 
						||
| 
								 | 
							
								    this._write(data);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Parser.prototype._header = function(name, val) {
							 | 
						||
| 
								 | 
							
								  /*if (name === 'content-disposition') {
							 | 
						||
| 
								 | 
							
								    this.field = grab(val, 'name');
							 | 
						||
| 
								 | 
							
								    this.file = grab(val, 'filename');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (this.file) {
							 | 
						||
| 
								 | 
							
								      this.data = stream(this.file, this.options.path);
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								      this.decode = new StringDecoder('utf8');
							 | 
						||
| 
								 | 
							
								      this.data = '';
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return this.emit('header', name, val);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Parser.prototype._write = function(data) {
							 | 
						||
| 
								 | 
							
								  /*if (this.data == null) {
							 | 
						||
| 
								 | 
							
								    return this._error('No disposition.');
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (this.file) {
							 | 
						||
| 
								 | 
							
								    this.data.write(data);
							 | 
						||
| 
								 | 
							
								    this.writtenDisk += data.length;
							 | 
						||
| 
								 | 
							
								  } else {
							 | 
						||
| 
								 | 
							
								    this.data += this.decode.write(data);
							 | 
						||
| 
								 | 
							
								    this.written += data.length;
							 | 
						||
| 
								 | 
							
								  }*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this.emit('data', data);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Parser.prototype._reset = function() {
							 | 
						||
| 
								 | 
							
								  this.pos = 0;
							 | 
						||
| 
								 | 
							
								  this.decode = null;
							 | 
						||
| 
								 | 
							
								  this.field = null;
							 | 
						||
| 
								 | 
							
								  this.data = null;
							 | 
						||
| 
								 | 
							
								  this.file = null;
							 | 
						||
| 
								 | 
							
								  this.header = null;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Parser.prototype._error = function(err) {
							 | 
						||
| 
								 | 
							
								  this.destroy();
							 | 
						||
| 
								 | 
							
								  this.emit('error', typeof err === 'string'
							 | 
						||
| 
								 | 
							
								    ? new Error(err)
							 | 
						||
| 
								 | 
							
								    : err);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Parser.prototype.destroy = function(err) {
							 | 
						||
| 
								 | 
							
								  this.writable = false;
							 | 
						||
| 
								 | 
							
								  this.readable = false;
							 | 
						||
| 
								 | 
							
								  this._reset();
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Parser.prototype._finish = function() {
							 | 
						||
| 
								 | 
							
								  var self = this
							 | 
						||
| 
								 | 
							
								    , field = this.field
							 | 
						||
| 
								 | 
							
								    , data = this.data
							 | 
						||
| 
								 | 
							
								    , file = this.file
							 | 
						||
| 
								 | 
							
								    , part;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this.pending++;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this._reset();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (data && data.path) {
							 | 
						||
| 
								 | 
							
								    part = data.path;
							 | 
						||
| 
								 | 
							
								    data.end(next);
							 | 
						||
| 
								 | 
							
								  } else {
							 | 
						||
| 
								 | 
							
								    part = data;
							 | 
						||
| 
								 | 
							
								    next();
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function next() {
							 | 
						||
| 
								 | 
							
								    if (!self.readable) return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    self.pending--;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    self.emit('part', field, part);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (data && data.path) {
							 | 
						||
| 
								 | 
							
								      self.emit('file', field, part, file);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (self.epilogue && !self.pending) {
							 | 
						||
| 
								 | 
							
								      self.emit('end');
							 | 
						||
| 
								 | 
							
								      self.destroy();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Uploads
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Parser.root = process.platform === 'win32'
							 | 
						||
| 
								 | 
							
								  ? 'C:/Temp'
							 | 
						||
| 
								 | 
							
								  : '/tmp';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Middleware
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Parser.middleware = function(options) {
							 | 
						||
| 
								 | 
							
								  options = options || {};
							 | 
						||
| 
								 | 
							
								  return function(req, res, next) {
							 | 
						||
| 
								 | 
							
								    if (options.ensureBody) {
							 | 
						||
| 
								 | 
							
								      req.body = {};
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (req.method === 'GET'
							 | 
						||
| 
								 | 
							
								        || req.method === 'HEAD'
							 | 
						||
| 
								 | 
							
								        || req._multipart) return next();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    req._multipart = true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var type = req.headers['content-type'];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (type) type = type.split(';')[0].trim().toLowerCase();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (type === 'multipart/form-data') {
							 | 
						||
| 
								 | 
							
								      Parser.handle(req, res, next, options);
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								      next();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Handler
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Parser.handle = function(req, res, next, options) {
							 | 
						||
| 
								 | 
							
								  var parser = new Parser(req.headers['content-type'], options)
							 | 
						||
| 
								 | 
							
								    , diskLimit = options.diskLimit
							 | 
						||
| 
								 | 
							
								    , limit = options.limit
							 | 
						||
| 
								 | 
							
								    , parts = {}
							 | 
						||
| 
								 | 
							
								    , files = {};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  parser.on('error', function(err) {
							 | 
						||
| 
								 | 
							
								    req.destroy();
							 | 
						||
| 
								 | 
							
								    next(err);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  parser.on('part', function(field, part) {
							 | 
						||
| 
								 | 
							
								    set(parts, field, part);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  parser.on('file', function(field, path, name) {
							 | 
						||
| 
								 | 
							
								    set(files, field, {
							 | 
						||
| 
								 | 
							
								      path: path,
							 | 
						||
| 
								 | 
							
								      name: name,
							 | 
						||
| 
								 | 
							
								      toString: function() {
							 | 
						||
| 
								 | 
							
								        return path;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  parser.on('data', function() {
							 | 
						||
| 
								 | 
							
								    if (this.writtenDisk > diskLimit || this.written > limit) {
							 | 
						||
| 
								 | 
							
								      this.emit('error', new Error('Overflow.'));
							 | 
						||
| 
								 | 
							
								      this.destroy();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  parser.on('end', next);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  req.body = parts;
							 | 
						||
| 
								 | 
							
								  req.files = files;
							 | 
						||
| 
								 | 
							
								  req.pipe(parser);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Helpers
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var isWindows = process.platform === 'win32';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var stream = function(name, dir) {
							 | 
						||
| 
								 | 
							
								  var ext = path.extname(name) || ''
							 | 
						||
| 
								 | 
							
								    , name = path.basename(name, ext) || ''
							 | 
						||
| 
								 | 
							
								    , dir = dir || Parser.root
							 | 
						||
| 
								 | 
							
								    , tag;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  tag = Math.random().toString(36).substring(2);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  name = name.substring(0, 200) + '.' + tag;
							 | 
						||
| 
								 | 
							
								  name = path.join(dir, name) + ext.substring(0, 6);
							 | 
						||
| 
								 | 
							
								  name = name.replace(/\0/g, '');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (isWindows) {
							 | 
						||
| 
								 | 
							
								    name = name.replace(/[:*<>|"?]/g, '');
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return fs.createWriteStream(name);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var grab = function(str, name) {
							 | 
						||
| 
								 | 
							
								  if (!str) return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var rx = new RegExp('\\b' + name + '\\s*=\\s*("[^"]+"|\'[^\']+\'|[^;,]+)', 'i')
							 | 
						||
| 
								 | 
							
								    , cap = rx.exec(str);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (cap) {
							 | 
						||
| 
								 | 
							
								    return cap[1].trim().replace(/^['"]|['"]$/g, '');
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Expose
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								module.exports = Parser;
							 |