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.
		
		
		
		
		
			
		
			
				
					111 lines
				
				2.9 KiB
			
		
		
			
		
	
	
					111 lines
				
				2.9 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								var EventEmitter = require('events').EventEmitter,
							 | 
						||
| 
								 | 
							
								    inherits = require('util').inherits;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var StreamSearch = require('streamsearch');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var B_DCRLF = new Buffer('\r\n\r\n'),
							 | 
						||
| 
								 | 
							
								    RE_CRLF = /\r\n/g,
							 | 
						||
| 
								 | 
							
								    RE_HDR = /^([^:]+):[ \t]?([\x00-\xFF]+)?$/,
							 | 
						||
| 
								 | 
							
								    MAX_HEADER_PAIRS = 2000, // from node's http.js
							 | 
						||
| 
								 | 
							
								    MAX_HEADER_SIZE = 80 * 1024; // from node's http_parser
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function HeaderParser(cfg) {
							 | 
						||
| 
								 | 
							
								  EventEmitter.call(this);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var self = this;
							 | 
						||
| 
								 | 
							
								  this.nread = 0;
							 | 
						||
| 
								 | 
							
								  this.maxed = false;
							 | 
						||
| 
								 | 
							
								  this.npairs = 0;
							 | 
						||
| 
								 | 
							
								  this.maxHeaderPairs = (cfg && typeof cfg.maxHeaderPairs === 'number'
							 | 
						||
| 
								 | 
							
								                         ? cfg.maxHeaderPairs
							 | 
						||
| 
								 | 
							
								                         : MAX_HEADER_PAIRS);
							 | 
						||
| 
								 | 
							
								  this.buffer = '';
							 | 
						||
| 
								 | 
							
								  this.header = {};
							 | 
						||
| 
								 | 
							
								  this.finished = false;
							 | 
						||
| 
								 | 
							
								  this.ss = new StreamSearch(B_DCRLF);
							 | 
						||
| 
								 | 
							
								  this.ss.on('info', function(isMatch, data, start, end) {
							 | 
						||
| 
								 | 
							
								    if (data && !self.maxed) {
							 | 
						||
| 
								 | 
							
								      if (self.nread + (end - start) > MAX_HEADER_SIZE) {
							 | 
						||
| 
								 | 
							
								        end = (MAX_HEADER_SIZE - self.nread);
							 | 
						||
| 
								 | 
							
								        self.nread = MAX_HEADER_SIZE;
							 | 
						||
| 
								 | 
							
								      } else
							 | 
						||
| 
								 | 
							
								        self.nread += (end - start);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (self.nread === MAX_HEADER_SIZE)
							 | 
						||
| 
								 | 
							
								        self.maxed = true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      self.buffer += data.toString('binary', start, end);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (isMatch)
							 | 
						||
| 
								 | 
							
								      self._finish();
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								inherits(HeaderParser, EventEmitter);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HeaderParser.prototype.push = function(data) {
							 | 
						||
| 
								 | 
							
								  var r = this.ss.push(data);
							 | 
						||
| 
								 | 
							
								  if (this.finished)
							 | 
						||
| 
								 | 
							
								    return r;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HeaderParser.prototype.reset = function() {
							 | 
						||
| 
								 | 
							
								  this.finished = false;
							 | 
						||
| 
								 | 
							
								  this.buffer = '';
							 | 
						||
| 
								 | 
							
								  this.header = {};
							 | 
						||
| 
								 | 
							
								  this.ss.reset();
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HeaderParser.prototype._finish = function() {
							 | 
						||
| 
								 | 
							
								  if (this.buffer)
							 | 
						||
| 
								 | 
							
								    this._parseHeader();
							 | 
						||
| 
								 | 
							
								  this.ss.matches = this.ss.maxMatches;
							 | 
						||
| 
								 | 
							
								  var header = this.header;
							 | 
						||
| 
								 | 
							
								  this.header = {};
							 | 
						||
| 
								 | 
							
								  this.buffer = '';
							 | 
						||
| 
								 | 
							
								  this.finished = true;
							 | 
						||
| 
								 | 
							
								  this.nread = this.npairs = 0;
							 | 
						||
| 
								 | 
							
								  this.maxed = false;
							 | 
						||
| 
								 | 
							
								  this.emit('header', header);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HeaderParser.prototype._parseHeader = function() {
							 | 
						||
| 
								 | 
							
								  if (this.npairs === this.maxHeaderPairs)
							 | 
						||
| 
								 | 
							
								    return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var lines = this.buffer.split(RE_CRLF), len = lines.length, m, h,
							 | 
						||
| 
								 | 
							
								      modded = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (var i = 0; i < len; ++i) {
							 | 
						||
| 
								 | 
							
								    if (lines[i].length === 0)
							 | 
						||
| 
								 | 
							
								      continue;
							 | 
						||
| 
								 | 
							
								    if (lines[i][0] === '\t' || lines[i][0] === ' ') {
							 | 
						||
| 
								 | 
							
								      // folded header content
							 | 
						||
| 
								 | 
							
								      // RFC2822 says to just remove the CRLF and not the whitespace following
							 | 
						||
| 
								 | 
							
								      // it, so we follow the RFC and include the leading whitespace ...
							 | 
						||
| 
								 | 
							
								      this.header[h][this.header[h].length - 1] += lines[i];
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								      m = RE_HDR.exec(lines[i]);
							 | 
						||
| 
								 | 
							
								      if (m) {
							 | 
						||
| 
								 | 
							
								        h = m[1].toLowerCase();
							 | 
						||
| 
								 | 
							
								        if (m[2]) {
							 | 
						||
| 
								 | 
							
								          if (this.header[h] === undefined)
							 | 
						||
| 
								 | 
							
								            this.header[h] = [m[2]];
							 | 
						||
| 
								 | 
							
								          else
							 | 
						||
| 
								 | 
							
								            this.header[h].push(m[2]);
							 | 
						||
| 
								 | 
							
								        } else
							 | 
						||
| 
								 | 
							
								          this.header[h] = [''];
							 | 
						||
| 
								 | 
							
								        if (++this.npairs === this.maxHeaderPairs)
							 | 
						||
| 
								 | 
							
								          break;
							 | 
						||
| 
								 | 
							
								      } else {
							 | 
						||
| 
								 | 
							
								        this.buffer = lines[i];
							 | 
						||
| 
								 | 
							
								        modded = true;
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  if (!modded)
							 | 
						||
| 
								 | 
							
								    this.buffer = '';
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								module.exports = HeaderParser;
							 |