UNPKG

whistle

Version:

HTTP, HTTPS, Websocket debugging proxy

168 lines (148 loc) 4.42 kB
var PassThrough = require('stream').PassThrough; var TIMEOUT = 36000; var MAX_BYTES = 1024 * 256; var CRLF_BUF = toBuffer('\r\n'); function toBuffer(buf) { return new Buffer(buf); } 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 formatHeaders(headers, rawHeaders) { if (!rawHeaders) { return headers; } var newHeaders = {}; if (Array.isArray(rawHeaders)) { var rawHeadersMap = {}; for (var i = 0, len = rawHeaders.length; i < len; i += 2) { var name = rawHeaders[i]; if (typeof name === 'string') { rawHeadersMap[name.toLowerCase()] = name; } } rawHeaders = rawHeadersMap; } Object.keys(headers).forEach(function(name) { newHeaders[rawHeaders[name] || name] = headers[name]; }); return newHeaders; } function getRawHeaderNames(rawHeaders) { var rawHeaderNames = {}; for (var i = 0, len = rawHeaders.length; i < len; i += 2) { var name = rawHeaders[i]; if (typeof name === 'string') { rawHeaderNames[name.toLowerCase()] = name; } } return rawHeaderNames; } module.exports = function parseReq(socket, callback, readBuffer, neadModifyHeaders) { if (typeof readBuffer == 'boolean') { var temp = neadModifyHeaders; neadModifyHeaders = readBuffer; readBuffer = temp; } var timeoutId, buffer; socket.on('error', callback); 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) { callback(new Error('Parse error')); } else { timeoutId = setTimeout(showTimeout, TIMEOUT); } return; } socket.removeListener('data', parseData); var req = neadModifyHeaders ? socket : new PassThrough(); var headers = {}; var rawHeaders = buffer.slice(0, endIndex).toString().trim().split(/\r\n/g); var firstLine = rawHeaders.shift(); var status = firstLine.split(/\s/g); req.rawHeaderNames = 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) { req.getBuffer = function(headers, path) { if (!headers) { return buffer; } if (path) { status[1] = path; path = status.join(' '); } var rawData = [path || firstLine]; headers = formatHeaders(headers, req.rawHeaderNames); Object.keys(headers).forEach(function(key) { var value = headers[key]; value && rawData.push(key + ':' + value); }); return Buffer.concat([toBuffer(rawData.join('\r\n')), buffer.slice(endIndex)]); }; } else { req.on('error', function () { socket.destroy(); }); req.destroy = function() { socket.destroy(); }; req.socket = socket; req.write(buffer); socket.pipe(req); } callback(null, req); } function showTimeout() { callback(new Error('Timeout')); } }; module.exports.formatHeaders = formatHeaders; module.exports.getRawHeaderNames = getRawHeaderNames;