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.
		
		
		
		
		
			
		
			
				
					99 lines
				
				2.7 KiB
			
		
		
			
		
	
	
					99 lines
				
				2.7 KiB
			| 
											3 years ago
										 | const EventEmitter = require('events').EventEmitter | ||
|  | const inherits = require('util').inherits | ||
|  | const getLimit = require('../../../lib/utils').getLimit | ||
|  | 
 | ||
|  | const StreamSearch = require('../../streamsearch/sbmh') | ||
|  | 
 | ||
|  | const B_DCRLF = Buffer.from('\r\n\r\n') | ||
|  | const RE_CRLF = /\r\n/g | ||
|  | const RE_HDR = /^([^:]+):[ \t]?([\x00-\xFF]+)?$/ // eslint-disable-line no-control-regex
 | ||
|  | 
 | ||
|  | function HeaderParser (cfg) { | ||
|  |   EventEmitter.call(this) | ||
|  | 
 | ||
|  |   cfg = cfg || {} | ||
|  |   const self = this | ||
|  |   this.nread = 0 | ||
|  |   this.maxed = false | ||
|  |   this.npairs = 0 | ||
|  |   this.maxHeaderPairs = getLimit(cfg, 'maxHeaderPairs', 2000) | ||
|  |   this.maxHeaderSize = getLimit(cfg, 'maxHeaderSize', 80 * 1024) | ||
|  |   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 >= self.maxHeaderSize) { | ||
|  |         end = self.maxHeaderSize - self.nread + start | ||
|  |         self.nread = self.maxHeaderSize | ||
|  |         self.maxed = true | ||
|  |       } else { self.nread += (end - start) } | ||
|  | 
 | ||
|  |       self.buffer += data.toString('binary', start, end) | ||
|  |     } | ||
|  |     if (isMatch) { self._finish() } | ||
|  |   }) | ||
|  | } | ||
|  | inherits(HeaderParser, EventEmitter) | ||
|  | 
 | ||
|  | HeaderParser.prototype.push = function (data) { | ||
|  |   const 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 | ||
|  |   const 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 } | ||
|  | 
 | ||
|  |   const lines = this.buffer.split(RE_CRLF) | ||
|  |   const len = lines.length | ||
|  |   let m, h | ||
|  | 
 | ||
|  |   for (var i = 0; i < len; ++i) { // eslint-disable-line no-var
 | ||
|  |     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 ...
 | ||
|  |       if (h) { | ||
|  |         this.header[h][this.header[h].length - 1] += lines[i] | ||
|  |         continue | ||
|  |       } | ||
|  |     } | ||
|  | 
 | ||
|  |     const posColon = lines[i].indexOf(':') | ||
|  |     if ( | ||
|  |       posColon === -1 || | ||
|  |       posColon === 0 | ||
|  |     ) { | ||
|  |       return | ||
|  |     } | ||
|  |     m = RE_HDR.exec(lines[i]) | ||
|  |     h = m[1].toLowerCase() | ||
|  |     this.header[h] = this.header[h] || [] | ||
|  |     this.header[h].push((m[2] || '')) | ||
|  |     if (++this.npairs === this.maxHeaderPairs) { break } | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | module.exports = HeaderParser |