whistle
Version:
HTTP, HTTP2, HTTPS, Websocket debugging proxy
99 lines (93 loc) • 3.48 kB
JavaScript
var fs = require('fs');
var path = require('path');
var Transform = require('pipestream').Transform;
var util = require('../util');
var config = require('../config');
var logScriptFile = path.join(config.ASSESTS_PATH, 'js/log.js');
var logScript = fs.readFileSync(logScriptFile, { encoding: 'utf8' });
var logScriptTag = '<script>' + logScript + '</script>\r\n';
var logHtmlScript = '<!DOCTYPE html>\r\n' + logScriptTag;
var LOG_ID_RE = /^log:\/\/(\{[^\s]{1,36}\}|[^/\\{}()<>\s]{1,36})$/;
function wrapScript(script, isHtml) {
return isHtml
? '\r\n<script>' + script + '</script>\r\n'
: '\r\n' + script + '\r\n';
}
function getScript(host, isHtml, req, noDoctype) {
host = util.getInternalHost(req, host);
var logCgiPath =
config.WEBUI_PATH + 'log.' + config.port + '/cgi-bin/log/set';
var result = isHtml ? (noDoctype ? logScriptTag : logHtmlScript) : logScript;
var baseUrl = (req.isHttps ? 'https://' : 'http://') + host;
return result.replace('$BASE_URL', baseUrl).replace('$LOG_CGI', logCgiPath);
}
module.exports = function (req, res) {
var log = req.rules.log;
if (log) {
util.disableReqCache(req.headers);
var host = req.headers.host;
delete req.rules.log;
res.on('src', function (_res) {
if (!(log = req.rules.log) || !util.hasBody(_res)) {
return;
}
var topScript, isHtml;
if (util.supportHtmlTransform(_res, req)) {
isHtml = true;
topScript = getScript(host, isHtml, req, util.isDisable(req, 'logDoctype'));
} else if (util.getContentType(_res.headers) == 'JS') {
topScript = getScript(host, isHtml, req, util.isDisable(req, 'logDoctype'));
}
if (topScript) {
var enable = req.enable;
topScript = topScript.split('$INTERCEPT_CONSOLE').join(!req.disable.interceptConsole || !!enable.interceptConsole);
!util.isEnable(req, 'keepAllCSP') && util.disableCSP(_res.headers);
!req._customCache && util.disableResStore(_res.headers);
var userScript;
var transform = new Transform();
var added;
transform._transform = function (chunk, _, callback) {
if (!added) {
added = true;
var logId = '';
var isValue;
if (LOG_ID_RE.test(log.matcher)) {
logId = RegExp.$1;
if (logId[0] === '{') {
logId = logId.slice(1, -1);
isValue = true;
}
try {
logId = encodeURIComponent(logId);
} catch (e) {}
}
util.getRuleValue(
logId && !isValue ? null : log,
function (script) {
topScript = topScript.replace('$LOG_ID', logId);
var buf = [util.toBuffer(topScript)];
userScript = script || null;
if (userScript) {
userScript = util.toBuffer(wrapScript(userScript, isHtml));
if (isHtml || !chunk) {
buf.push(userScript);
userScript = null;
}
}
chunk && buf.push(chunk);
callback(null, Buffer.concat(buf));
},
null,
null,
null,
req
);
} else {
callback(null, chunk || userScript);
}
};
res.addZipTransform(transform, false, true);
}
});
}
};