Trying to learn more about node.js by making a simple http proxy server. The use scenario is simple: user -> proxy -> server -> proxy -> user
The following code works until the last step. Couldn't find way to pipe connector's output back to the user.
#!/usr/bin/env node
var
url = require('url'),
http = require('http'),
acceptor = http.createServer().listen(3128);
acceptor.on('request', function(request, response) {
console.log('request ' + request.url);
request.pause();
var options = url.parse(request.url);
options.headers = request.headers;
options.method = request.method;
options.agent = false;
var connector = http.request(options);
request.pipe(connector);
request.resume();
// connector.pipe(response); // doesn't work
// connector.pipe(request); // doesn't work either
});
Using tcpflow I see the incoming request from the browser, then the outgoing proxy request, then the server response back to the proxy. Somehow i couldn't manage to retransmit the response back to the browser.
What is the proper way to implement this logic with pipes?
you dont have to 'pause', just 'pipe' is ok
var connector = http.request(options, function(res) {
res.pipe(response, {end:true});//tell 'response' end=true
});
request.pipe(connector, {end:true});
http request will not finish until you tell it is 'end';
OK. Got it.
UPDATE: NB! As reported in the comments, this example doesn't work anymore. Most probably due to the Streams2 API change (node 0.9+)
Piping back to the client has to happen inside connector's callback as follows:
#!/usr/bin/env node
var
url = require('url'),
http = require('http'),
acceptor = http.createServer().listen(3128);
acceptor.on('request', function(request, response) {
console.log('request ' + request.url);
request.pause();
var options = url.parse(request.url);
options.headers = request.headers;
options.method = request.method;
options.agent = false;
var connector = http.request(options, function(serverResponse) {
serverResponse.pause();
response.writeHeader(serverResponse.statusCode, serverResponse.headers);
serverResponse.pipe(response);
serverResponse.resume();
});
request.pipe(connector);
request.resume();
});
I used the examples from this post to proxy http/s requests. Faced with the problem that cookies were lost somewhere.
So to fix that you need to handle headers from the proxy response.
Below the working example:
const http = require('http');
const acceptor = http.createServer().listen(3128);
acceptor.on('request', function(request, response) {
const req = service.request(options, function(res) {
response.writeHead(res.statusCode, res.headers);
return res.pipe(response, {end: true});
});
request.pipe(req, {end: true});
});
Related
What I'm trying to do:
I'm trying to create a proxy in node.js where I can inspect the content of an HTTP request before forwarding it to my target server.
What I have tried so far:
I have created this function "getContent(req)" which gives me the content of the request, so that I can inspect it and decide if I want to forward it to the target server.
function getContent(req) {
return new Promise((resolve, reject) => {
let body = [];
let textDecoder = new TextDecoder();
req.on('data', (chunk) => {
body.push(textDecoder.decode(chunk));
});
req.on('end', () => {
resolve(body.join(''));
});
});
}
The problem I'm stuck with:
The function works and I do get the content of the request, but this consumes the stream, so I can no longer forward the http.IncomingMessage to my target server.
Code of the proxy that will forward the request for reference:
const http = require('http');
const httpProxy = require('http-proxy');
var proxy = httpProxy.createProxyServer({
target: 'http://127.0.0.1:7545'
});
var server = http.createServer(
async function (req, res) {
/** If I remove this line, the proxy request forwarding works,
* but I need to inspect the content of the request before forwarding! */
let content = await getContent(req);
console.log(`${content} - processing request!`);
proxy.web(req, res);
});
So in conclusion, how to read the content of a http.IncomingMessage (ReadableStream) without consuming it in node.js, so that I can then still forward the request to a target server?
The concept is simple, creating a http server that forward websocket request to another port.
Here is the code on my server side:
http.createServer(onRequest).listen(9999);
function onRequest(request, response) {
console.log(request);
...
}
So if the http server receive any request at all it should print out the request in console.
Then on the client side (also a node.js application), the code is:
var HttpsProxyAgent = require('https-proxy-agent');
var WebSocket = require('ws');
...
var proxy = `http://${config.proxy.host}:${config.proxy.port}`;
var options = url.parse(proxy);
agent = new HttpsProxyAgent(options);
ws = new WebSocket(target, {
protocol: 'binary',
agent: agent
});
Now, when I use Charles to intercept the request, the client did indeed emit a request, here is the curl form captured by Charles:
curl -H 'Host: target.host.com:8080' -X CONNECT 'https://target.host.com:8080'
the problem seems to be that
function onRequest(request, response) {
console.log(request);
...
}
didn't actually receive any -X CONNECT 'https://proxy.host.com:9999' request, or at least it didn't print it out (obviously it didn't work either).
var server = http.createServer(onRequest).listen(9999);
server.on('connect', (req, cltSocket, head) => {
const srvSocket = net.connect('8080', '127.0.0.1', () => {
cltSocket.write('HTTP/1.1 200 Connection Established\r\n' +
'Proxy-agent: Node.js-Proxy\r\n' +
'\r\n');
srvSocket.write(head);
srvSocket.pipe(cltSocket);
cltSocket.pipe(srvSocket);
});
});
How do I use http module to make GET requests with a query string and cookies?
GET someurl?test=one
Cookies: name=john; name1=mary;
var http = require('http');
var url_parser = require("url");
var url = "someurl?test=one";
var url_parts = url_parser.parse(url);
var options = {host: url_parts.hostname, port: url_parts.port|80, path: url_parts.path};
var request = http.request(options, function(response) {
//do something with the response
}).on('error',function(e){
//error happened
});
request.setHeader( 'cookie', YOUR_COOKIE );
request.end();
I am learning Node.JS and this is the most commonly available example of server by Node.JS
// Load the http module to create an http server.
var http = require('http');
// Configure our HTTP server to respond with Hello World to all requests.
var server = http.createServer(function (request, response) {
// var name=request.getParameter('name');
// console.log(name);
console.log('res: ' + JSON.stringify(response.body));
response.writeHead(200, {"Content-Type": "text/plain"});
response.end("Hello World\n");
});
// Listen on port 8000, IP defaults to 127.0.0.1
server.listen(8000);
Now when I am executing this from console it works fine, and from browser also it works fine, by hitting the URL: localhost:8000
But now I also want to send some parameters to this server, so I tried localhost:8000/?name=John and few more URL's but none of them work, Can anyone help me?
Thanks in advance!!
try:
var url = require('url');
var name = url.parse(request.url, true).query['name'];
Node's HTTP API is rather low-level compared to other frameworks/environments that you might be familiar with, so pleasantries like a getParameter() method don't exist out of the box.
You can get the query-string from the request's url, which you can then parse:
var http = require('http');
var url = require('url');
var server = http.createServer(function (request, response) {
var parsedUrl = url.parse(request.url, true);
var query = parsedUrl.query;
console.log(query.name);
// ...
});
I am trying to access the body of a json page that has a callback url.
In client side it is easy by using jquery and using jsonp option and so on...
How do i do it on the nodejs server side to get the title for example??
the url prints out: data({"log":{"title":"example","description" ...
var http = require("http");
function getPost(){
var reqest = http.get("http://news.example.com/api/read/json?callback=data", function(response){
response.setEncoding('utf8');
response.on('data', function(posts){
var x = JSON.parse(posts);
var callback = function(x){
console.log(callback);
}
});
});
}
getPost();