Get response from proxy server - node.js

I created a proxy server in node.js using the node-http-proxy module.
Looks like this:
var http = require('http'),
httpProxy = require('http-proxy'),
io = require("socket.io").listen(5555);
var proxy = new httpProxy.RoutingProxy();
http.createServer(function (req, res) {
proxy.proxyRequest(req, res, {
host: 'localhost',
port: 1338
});
}).listen(9000);
So, I need, before sending the response back to the client to get the body from the server that I proxy and analyze it.
But I can't find event or attribute, where I can get this data. I tried:
proxy.on('end', function (data) {
console.log('end');
});
But I can't figure our how to get the mime body from it.

If all you want to do is examine the response (read-only) , you could use :
proxy.on('proxyRes', function(proxyRes, req, res){
proxyRes.on('data' , function(dataBuffer){
var data = dataBuffer.toString('utf8');
console.log("This is the data from target server : "+ data);
});
});
But , note that the 'proxyRes' event is emitted after the response is sent.
Reference in :
https://github.com/nodejitsu/node-http-proxy/issues/382

I found answer:
I rewrite response function for body -
var http = require('http'),
httpProxy = require('http-proxy'),
io = require("socket.io").listen(5555);
var proxy = new httpProxy.RoutingProxy();
http.createServer(function (req, res) {
console.log(req.url);
res.oldWrite = res.write;
res.write = function(data) {
/* add logic for your data here */
console.log(data.toString('UTF8'));
res.oldWrite(data);
}
proxy.proxyRequest(req, res, {
host: 'localhost',
port: 1338
});
}).listen(9000);
This code will console all url request and response form this endpoint.

Based on the answer of #Psycho, following code can be used to modify headers as well
var server = http.createServer(function(req, res) {
res.oldWrite = res.write;
res.write = function(data) {
console.log(data.toString('UTF8'));
res.oldWrite(data);
}
res.oldSetHeader = res.setHeader
res.setHeader = function(k,v) {
console.log(k,v)
res.oldSetHeader(k,v)
}
proxy.web(req, res, { target: proxyPool[key]}); })

Related

Want to write capture and re-transmit http/https request to Browser?

I want to write a simple Node Js application which will capture and re-transmit http/https request to Browser?
I have written the below code, but it works only for http request.
var server = http.createServer(function (req,res) {
console.log("start request:", req.url);
var option = url.parse(req.url);
option.headers = req.headers;
var proxyrequest = http.request(option, function (proxyresponce) {
proxyresponce.on('data', function (chunk) {
console.log("proxy responce length" ,chunk.length);
res.write(chunk,'binary');
});
proxyresponce.on('end',function () {
console.log("proxy responce ended");
res.end();
});
res.writeHead(proxyresponce.statusCode, proxyresponce.headers);
});
});

Nodejs - BrowserSync running on express server

I want to pull a URL from the DB and use it as the proxied URL. However the setup I've come up with initializes a new BrowserSync server for each URL, using incrementing port numbers.
Is there a way to accomplish this without initializing a new BrowserSync server every time?
Or should I be using another approach?
var bs = require("browser-sync");
var express = require("express");
var router = express.Router();
var app = express();
router.get("/", function(req, res){
var proxyUrl = getUrl() //get url from db (www.example.com)
bs.create("bs1").init({
notify: false,
open: false,
ui: false,
port: 10000,
proxy: proxyUrl
});
res.send();
});
app.use(router);
app.listen(8080, function(){
console.log('listening on *:8080');
});
The above is fine(ish) but is it good practice to be initializing a new server for every URL (potentially thousands)?
And is it safe to be exposing a new port number to every user of the system? (Can I mask this with a subdomain?)
Update
My end goal is to use a unique subdomain to refer to each proxy url.
For example:
sub1.mysite.com proxies www.example.com,
sub2.mysite.com proxies www.example2.com
Browser-sync will not work as the proxy is tie to server setup.
I use following packages:
express
express-http-proxy
vhost (express vhost)
const port = 8080;
var app = require('express')();
var proxy = require('express-http-proxy');
var url = require('url');
var vhost = require('vhost');
app.listen(port);
/* Assuming getUrl() will return an array of sites */
// var sites = getUrl();
// DO NOT put '/' at the end of site
var sites = [
'http://www.bing.com',
'http://samanthagooden.com',
'http://www.courtleigh.com'
];
var i = 0;
sites.forEach(site => {
i++;
var subDomain = 'sub' + i + '.mysite.com';
app.use(vhost(subDomain, proxy(site, {
forwardPath: (req, res) => url.parse(req.url).path,
intercept: (rsp, data, req, res, callback) => {
if (res._headers['content-type']) {
var contentType = res._headers['content-type'];
if (
contentType.indexOf('text') !== -1 ||
contentType.indexOf('javascript') !== -1
) {
// Replace link if content-type = text or javascript
var reg = new RegExp(site, 'g');
res.send(data.toString().replace(reg, ''));
} else {
res.send(data);
}
} else {
res.send(data);
}
}
})));
console.log(subDomain + ':' + port + ' proxy: ' + site);
});
The above example will create following proxies:
sub1.mysite.com:8080 proxy: www.bing.com
sub2.mysite.com:8080 proxy: www.example.com
Maybe I'm misunderstanding what you are trying to do, but Browsersync and express seems a bit overkill in this case, why not just use node-http-proxy with the native http module?
var http = require('http')
var httpProxy = require('http-proxy')
var options = ...
var proxy = httpProxy.createProxyServer(options)
var server = http.createServer(function (req, res) {
var proxyUrl = getUrl()
proxy.web(req, res, { target: proxyUrl })
})
server.listen(8080, function () {
console.log('listening on *:8080')
})
As per me If you want SAAS service using proxy is not the good idea to go is what am thinking.. if you are going with proxy for each client will create process with new port... My Solution is to create node server with listen localhost and map *.domain.com to the server..
If you are using individual database for each client :-
in node logic get cname from request host and use that reference to connect database.
Final Controller code would be..
var express = require('express');
var router = express.Router();
var MongoClient = require('mongodb').MongoClient;
/* GET home page. */
router.get('/', function(req, res, next) {
var client = req.subdomains[0];
console.log(client);
MongoClient.connect('mongodb://localhost:27017/'+client, function(err, db) {
if (err) {
throw err;
}
db.collection('app1').find().toArray(function(err, result) {
if (err) {
throw err;
}
console.log('data');
console.log(result);
});
});
res.render('index', { title: 'Express' });
});
module.exports = router;
~
~
In future if you get more clients you can implement node cluster or standard Ubuntu cluster using webservice

Access control origin in connect (node.js)

I am running static pages via connect
var connect = require('connect');
connect.createServer(
connect.static(__dirname)).listen(8080);
I have to add a response header to the above code to bypass the access control
response.writeHead(200, {
'Content-Type': 'text/html',
'Access-Control-Allow-Origin' : '*'});
How do I add it to the above connect code.
I answered this question here
Relevant code
var http = require("http");
var connect = require('connect');
var app = connect()
.use(connect.logger('dev'))
.use(connect.static('home'))
.use(function(req, res){
res.setHeader("Access-Control-Allow-Origin", "http://example.com");
res.end('hello world\n');
});
var server = http.createServer(app);
server.listen(9999, function () {
console.log('server is listening');
});
Enable cors provides excellent resource for adding cors to your server.
If you got to send the cors headers with every static file that you serve and you have to use connect then do this
navigate to connect\node_modules\send\lib\send.js
look for the setHeader function in the file. This is the function that actually sets header to your static resources. Just add
res.setHeader("Access-Control-Allow-Origin", "your domain");
and all of your files will have the cors header in them
If you are just using connect to serve static files and don't require any of the other functionality consider using send instead. This way you will have access to all of it's methods directly and won't need to edit files. You can simply add headers from your create server method. Here is the sample code
var http = require("http");
var connect = require('connect');
var send = require('send');
var url = require('url');
var app = http.createServer(function(req, res){
// your custom error-handling logic:
function error(err) {
res.statusCode = err.status || 500;
res.end(err.message);
}
// your custom directory handling logic:
function redirect() {
res.statusCode = 301;
res.setHeader('Location', req.url + '/');
res.end('Redirecting to ' + req.url + '/');
}
function setRoot(){
res.setHeader("Access-Control-Allow-Origin",
"http://example.com");
return './public';
}
function setIndex(){
res.setHeader("Access-Control-Allow-Origin",
"http://example.com");
return '/index.html';
}
send(req, url.parse(req.url).pathname)
.root(setRoot()).index(setIndex())
.on('error', error)
.on('directory', redirect)
.pipe(res);
}).listen(3000);

node js incoming request sourceIP

For example:
http.createServer(function (request, response) {
request.on("end", function () {
});
});
Using Request, how I can I find the source IP of the request?
Depending on whether the request is made by a proxy forward or direct connection the source ip address may be stored at different places. You have to check req.header['x-forwarded-for'] first and then req.connection.remoteAddress. An example function is shown in this gist.
Here is a working example:
var http = require('http');
var getClientIp = function(req) {
var ipAddress = null;
var forwardedIpsStr = req.headers['x-forwarded-for'];
if (forwardedIpsStr) {
ipAddress = forwardedIpsStr[0];
}
if (!ipAddress) {
ipAddress = req.connection.remoteAddress;
}
return ipAddress;
};
var server = http.createServer();
server.on('request', function(req, res) {
console.log(getClientIp(req));
res.writeHead(200, {'Content-Type': 'text/plain'});
return res.end('Hello World\n');
});
server.listen(9000, 'localhost');
the getClientIp function was taken from here with some minor changes. Note that the contents of x-forwarded-for is an array containing proxy IPs, (read more here), so you may wish to inspect more than the first element.

node.js, callback on the end of an http-proxy request?

I'm trying to learn node.js, and my context is the http-proxy module from nodejitsu.
I'd like to get access to the end of the proxy event, so that I can log how long the target server took to respond. However, I can't out how to create the appropriate callback or event handler. I've looked at the source for http-proxy, and it doesn't seem to take the conventional callback method.
Here's a sample, I'm sure its a simple fix to someone that breaths Node:
/* demonstrate a basic proxy server that can log the time
it takes to execute a given hit on the destination server
*/
var http = require('http'),
httpProxy = require('http-proxy');
// Create the proxy server
httpProxy.createServer(function (req, res, proxy) {
var startTime = ( new Date()).getTime();
// NEED HELP HERE.
// something like this should do it?
proxy.addListener("end",function() {
var endTime = (new Date()).getTime();
console.log("request took " + (endTime - startTime) + "ms");
});
proxy.proxyRequest(req, res, {
host: 'localhost',
port: 9000
});
}).listen(8000);
// the destination server
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully proxied: ' + req.url +'\n' + JSON.stringify(req.headers, true, 2));
// make the hit slow by pausing the end()
setTimeout(function() {
res.end();
},2000);
}).listen(9000);
One approach is to intercept the res.end() call. I have like 3 days of express experience, so I don't know what this will screw up:
var proxy = new httpProxy.RoutingProxy();
app.get("/foo", function (req, res) {
var realEnd = res.end;
var start = +new Date();
res.end = function () {
var elapsed = +new Date() - start;
console.log("elapsed", elapsed);
realEnd.apply(res);
}
proxy.proxyRequest(req, res, {
host: 'localhost',
port: 9000
});
});

Resources