UNPKG

whistle

Version:

HTTP, HTTP2, HTTPS, Websocket debugging proxy

182 lines (169 loc) 4.83 kB
var fs = require('fs'); var path = require('path'); var AdmZip = require('adm-zip'); var util = require('./util'); var fiddlerAssets = path.join(__dirname, '../../assets/fiddler/'); var fiddlerMeta = fs.readFileSync(fiddlerAssets + 'meta.xml', 'utf8'); var SPEC_XML_RE = /[<>&"']/g; var specMap = { '<': '&lt;', '>': '&gt;', '&': '&amp;', '\'': '&apos;', '"': '&quot;' }; var META_NAMES = [ 'ClientConnected', 'ClientDoneRequest', 'ServerGotRequest', 'ServerBeginResponse', 'ServerDoneResponse', 'ClientBeginResponse', 'ClientDoneResponse' ]; var META_NAMES2 = ['GatewayTime', 'DNSTime', 'TCPConnectTime', 'ttfb', 'ttlb', 'transfer-size', 'clientip', 'hostip']; function filterSessions(sessions) { return sessions.filter(function (item) { return item && item.url && item.req && item.startTime >= 0; }); } function renderTpl(tpl, locals) { locals = getMetaData(locals); Object.keys(locals).forEach(function (name) { tpl = tpl.replace('${' + name + '}', locals[name]); }); return tpl; } function escapeXml(str) { if (!str || typeof str !== 'string') { return ''; } return str.replace(SPEC_XML_RE, function(char) { return specMap[char] || char; }); } function getMetaData(item) { var meta = { SID: item.index + 1 }; META_NAMES.forEach(function (name) { meta[name] = '0001-01-01T00:00:00'; }); META_NAMES2.forEach(function (name) { meta[name] = 0; }); var comment = item.customData && item.customData.comment; meta['ui-comments'] = escapeXml(comment); meta.ClientConnected = util.toISOString(item.startTime); if (item.dnsTime >= item.startTime) { meta.DNSTime = item.dnsTime - item.startTime; } if (item.requestTime > 0) { meta.ClientDoneRequest = meta.ServerGotRequest = meta.ServerBeginResponse = util.toISOString(item.requestTime); } if (item.responseTime > 0) { meta.ClientBeginResponse = util.toISOString(item.responseTime); meta.ttfb = item.responseTime - item.startTime; } if (item.ttfb >= 0) { meta.ttfb = item.ttfb; } if (item.endTime > 0) { meta.ServerDoneResponse = meta.ClientDoneResponse = util.toISOString( item.endTime ); meta.ttlb = item.endTime - item.startTime; } var req = item.req || {}; var res = item.res || {}; if (res.size > 0) { meta['transfer-size'] = res.size; } meta.clientip = req.ip || '127.0.0.1'; meta.hostip = res.ip || ''; meta.clientport = req.port || 0; meta.serverport = res.port || 0; return meta; } function getFiddler2Meta(item) { return renderTpl(fiddlerMeta, item); } module.exports = function (body, callback) { var sessions = body; if (!Array.isArray(sessions)) { sessions = util.parseJSON(body.sessions); if (!Array.isArray(sessions)) { return ''; } } sessions = filterSessions(sessions); var index = 0; var getName = function () { var name = String(index); ++index; var paddingCount = 4 - name.length; return paddingCount <= 0 ? name : new Array(paddingCount + 1).join('0') + name; }; var zip = new AdmZip(); sessions.map(function (item, index) { item.req.url = item.url; var req = util.getReqRaw(item.req); var res = !item.res || item.res.statusCode == null ? Buffer.from('') : util.getResRaw(item.res); var name = getName(); item.index = index; zip.addFile('raw/' + name + '_c.txt', req); zip.addFile('raw/' + name + '_m.xml', Buffer.from(getFiddler2Meta(item))); zip.addFile('raw/' + name + '_s.txt', res); zip.addFile( 'raw/' + name + '_whistle.json', Buffer.from( JSON.stringify({ version: item.version, nodeVersion: item.nodeVersion, customData: item.customData, url: item.url, realUrl: item.realUrl, fwdHost: item.fwdHost, rules: item.rules, frames: item.frames, useHttp: item.useHttp, httpsTime: item.httpsTime, useH2: item.useH2, mark: item.mark, sniPlugin: item.sniPlugin, trailers: item.res && item.res.trailers, rawTrailerNames: item.res && item.res.rawTrailerNames, captureError: item.captureError, reqError: item.reqError, resError: item.resError, times: { startTime: item.startTime, dnsTime: item.dnsTime, requestTime: item.requestTime, responseTime: item.responseTime, endTime: item.endTime } }) ) ); }); var done; var handleCallback = function(err, body) { if (done) { return; } done = true; callback(err, body); }; return zip.toBuffer(function(body) { handleCallback(null, body); }, handleCallback); };