UNPKG

hparser

Version:
173 lines (154 loc) 4.68 kB
var PassThrough = require('stream').PassThrough; var util = require('./util'); var TIMEOUT = 36000; var MAX_BYTES = 1024 * 256; var CRLF_BUF = util.toBuffer('\r\n'); var BODY_SEP = util.toBuffer('\r\n\r\n'); function parsePairs(pairs, buffer) { var rawHeaders = []; for (var i = 0, len = buffer.length; i < len; i++) { var pair = getPair(buffer[i], rawHeaders); if (pair) { var value = pairs[pair.key]; if (value) { if (!Array.isArray(value)) { value = [value]; } value.push(pair.value); } pairs[pair.key] = value || pair.value; } } return rawHeaders; } function getPair(line, rawHeaders) { if (!(line = line && line.trim())) { return; } var index = line.indexOf(':'); var key = line.substring(0, index).trim(); var value = line.substring(index + 1).trim(); rawHeaders.push(key, value); return index != -1 ? { key: key.toLowerCase(), value: value } : null; } function endIndexOf(buffer, start, end) { start = start || 0; end = end || buffer.length; for (; start < end; start++) { if (buffer[start] == CRLF_BUF[0] && buffer[start + 1] == CRLF_BUF[1] && buffer[start + 2] == CRLF_BUF[0] && buffer[start + 3] == CRLF_BUF[1]) { return start; } } return -1; } function getRawHeaders(headers) { var rawData = []; Object.keys(headers).forEach(function(key) { var value = headers[key]; if (Array.isArray(value)) { value.forEach(function(val) { rawData.push(key + ': ' + (val || '')); }); } else { rawData.push(key + ': ' + (value || '')); } }); return rawData.join('\r\n'); } module.exports = function parseReq(socket, callback, readBuffer, neadModifyHeaders) { if (typeof readBuffer == 'boolean') { var temp = neadModifyHeaders; neadModifyHeaders = readBuffer; readBuffer = temp; } var timeoutId, buffer, done; var execCallback = function(err, req) { if (done) { return; } done = true; if (typeof callback === 'function') { if (!err && !req) { err = new Error('Closed'); } callback(err, req); } }; socket.on('error', execCallback); socket.on('close', execCallback); socket.on('data', parseData); readBuffer && parseData(readBuffer); function parseData(data) { clearTimeout(timeoutId); buffer = buffer ? Buffer.concat([buffer, data]) : data; var endIndex = endIndexOf(buffer); if (endIndex == -1) { if (buffer.length > MAX_BYTES) { execCallback(new Error('Parse error')); } else { timeoutId = setTimeout(showTimeout, TIMEOUT); } return; } socket.removeListener('data', parseData); var req = neadModifyHeaders ? socket : new PassThrough(); var headers = {}; var headersBuffer = buffer.slice(0, endIndex); var bodyBuffer = buffer.slice(endIndex + 4); var rawHeaders = headersBuffer.toString().trim().split(/\r\n/g); var firstLine = rawHeaders.shift(); var status = firstLine.split(/\s/g); req.bodyBuffer = bodyBuffer; req.headersBuffer = headersBuffer; req.body = bodyBuffer.toString(); req.rawHeaderNames = util.getRawHeaderNames(parsePairs(headers, rawHeaders)); req.method = status[0] = status[0] || 'GET'; req.url = status[1] || '/'; req.statusCode = status[1] || 0; req.httpVersion = status[2] && status[2].split('/')[1] || '1.1'; req.headers = headers; if (neadModifyHeaders) { var getHeaders = function(headers, path) { if (!headers) { return headersBuffer; } if (path) { status[1] = path; path = status.join(' '); } headers = util.formatHeaders(headers, req.rawHeaderNames); var rawData = [path || firstLine, getRawHeaders(headers)].join('\r\n'); var head = rawData.charCodeAt(); if (head < 32 || head === 127) { rawData = rawData.substring(1); } return util.toBuffer(rawData); }; req.getHeaders = function (headers, path) { return Buffer.concat([getHeaders(headers, path), BODY_SEP]); }; req.getBuffer = function(headers, path) { return Buffer.concat([getHeaders(headers, path), buffer.slice(endIndex)]); }; } else { req.on('error', function () { socket.destroy(); }); req.destroy = function() { socket.destroy(); }; req.socket = socket; req.write(buffer); socket.pipe(req); } execCallback(null, req); } function showTimeout() { execCallback(new Error('Timeout')); } }; module.exports.getRawHeaders = getRawHeaders;