proxy-tamper
Version:
A HTTP proxy library for node.js that allows for selective requests to be tampered.
154 lines (132 loc) • 4.32 kB
JavaScript
var http = require('http');
var ProxyTamper = function (options) {
var _patterns = [];
var sockets = {};
var nextSocketId = 0;
var _server = http.createServer(function (req, resp) {
var proxy = null;
var proxyReq = null;
var tamperBody = null;
var buffers = [];
var chunks = [];
var body = '';
var interceptRequest = function () {
_patterns.forEach(function (p) {
if (req.url.search(p.pattern) != -1) {
switch (p.tamper.constructor.name) {
case 'Function':
switch (parseInt(p.tamper.length)) {
case 1:
var reqProxyObj = {
method: req.method,
url: req.url,
headers: req.headers,
body: body,
onResponse: function (thisOnResultHandler) {
resp._onResultHandler = thisOnResultHandler;
}
};
p.tamper.call(null, reqProxyObj);
req.url = reqProxyObj.url;
req.headers = reqProxyObj.headers;
req.method = reqProxyObj.method;
break;
case 0:
default:
tamperBody = p.tamper.call(null, null);
break;
}
break;
case 'String':
tamperBody = p.tamper; break;
default:
throw new Error('Tamper object must be a function or string but was a '
+ p.tamper.constructor.name + '.'); break;
}
}
});
if (!resp._onResultHandler && tamperBody) {
resp.writeHead(200, {});
resp.write(tamperBody, 'utf8');
resp.end();
return;
}
var host = req.headers['host'].split(':')[0] || req.headers['host'];
var options = {
'host': host,
'port': parseInt(req.headers['host'].split(':')[1] || 80),
'path': req.url.replace(new RegExp('^https?:\/\/' + req.headers['host']), ''),
'method': req.method,
'headers': req.headers
};
proxyReq = http.request(options, function (proxyResp) {
proxyResp.on('data', function (chunk) { buffers.push(chunk); });
proxyResp.on('error', function (e) {});
proxyResp.on('end', function () {
var strBody = '';
buffers.forEach(function (buf) { strBody += buf.toString(); });
var originalStrBody = strBody;
var proxyRespProxyObj = {
statusCode: proxyResp.statusCode, headers: proxyResp.headers, body: strBody,
complete: function () {
resp.writeHead(this.statusCode, this.headers);
if ((strBody != this.body) && (this.body != undefined)) {
resp.write(this.body);
}
else {
buffers.forEach(function (buf) {
resp.write(buf, 'utf8');
});
}
resp.end();
}
};
if (resp._onResultHandler) {
resp._onResultHandler.call(null, proxyRespProxyObj);
}
else {
proxyRespProxyObj.complete.call(proxyRespProxyObj);
}
});
});
proxyReq.on('error', function (e) {
console.log('error: ' + e.message + ' when fetching url: ' + req.url);
resp.writeHead(502, this.headers);
resp.end()
});
chunks.forEach(function (chunk) { proxyReq.write(chunk); });
proxyReq.end();
}
req.on('data', function (chunk) {
chunks.push(chunk);
});
req.on('end', function () {
chunks.forEach(function (chunk) {
body += chunk.toString();
});
interceptRequest();
});
}).listen(options.port);
_server.on('connection', function (socket) {
var socketId = nextSocketId++;
sockets[socketId] = socket;
socket.on('close', function () {
delete sockets[socketId];
});
});
return {
tamper: function (pattern, obj) {
_patterns.unshift({ pattern: pattern, tamper: obj });
},
end: function () {
for (var socketId in sockets) {
sockets[socketId].destroy();
}
_server.close();
}
};
}
exports.start = function (options) {
var proxyTamper = new ProxyTamper(options);
return proxyTamper;
};