node js http createServer socket - node.js

The doubt with with code is two things:
When i send request through a browser, i dont get a console log message as "connected" but if i use http.get() or http.request() , it works fine
2)The "connect" event receives a callback with req,clientSocke,head ! now where can i see the server socket ?
const http=require("http")
const server=http.createServer()
server.on("connect",(req,c_socket,head)=>{
console.log("connected")
})
server.listen(5000,()=>{console.log("server up)})

when you access the server via browser, the method is using GET not CONNECT. That's why console.log does not show.
if you want console.log to show when accessing from the browser, you can use request event.
this is an explanation from node.js docs.
'connect' event is emitted each time a server responds to a request
with a CONNECT method. If this event is not being listened for,
clients receiving a CONNECT method will have their connections closed.
node.js docs
you can make a socket server with a net package with createSever method.
this is an example of how to make a simple request to the socket server.
const http = require('http');
const net = require('net');
const { URL } = require('url');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('hello world');
});
server.on('connect', (req, clientSocket, head) => {
console.log('connected');
// Connect to an origin server
const { port, hostname } = new URL(`http://${req.url}`);
const serverSocket = net.connect(port || 80, hostname, () => {
clientSocket.write(
'HTTP/1.1 200 Connection Established\r\n' +
'Proxy-agent: Node.js-Proxy\r\n' +
'\r\n'
);
serverSocket.write(head);
serverSocket.pipe(clientSocket);
clientSocket.pipe(serverSocket);
});
});
server.listen(5000, () => {
console.log('server up');
});
// Make a request to a tunneling server
const req = http
.request({
port: 5000,
host: 'localhost',
method: 'CONNECT',
path: 'www.google.com:80',
})
.end();
req.on('connect', (res, socket, head) => {
console.log('got connected!');
// Make a request over an HTTP tunnel
socket.write(
'GET / HTTP/1.1\r\n' +
'Host: www.google.com:80\r\n' +
'Connection: close\r\n' +
'\r\n'
);
socket.on('data', (chunk) => {
console.log(chunk.toString());
});
socket.on('end', () => {
console.log('end');
});
});

Related

Express and Websocket to run on the same port on the same file

I'm running two apps that sends real-time messages to each other using websocket and also generate a random link using express.js, now i hosted the server with both react apps to my vps host and want to make the websocket connection secure (wss://) but i realize i'll have to get the express server on the same port too, so the ssl/tsl works for both - so how do i do that?
Here is my full code, all on the same file:
const webSocketServerPort = 8000;
const webSocketServer = require('websocket').server;
const http = require('http');
const server = http.createServer(); server.listen(webSocketServerPort); console.log('Listening on port 8000');
const wsServer = new webSocketServer({ httpServer: server })
//GEERTOOOO
const express = require('express'); const cors = require('cors'); const fs = require('fs'); const app = express();
app.use(cors({ origin: '*' }));
app.get('/', (req, res) => { // Generate a random 6-character string const linkId = Math.random().toString(36).substr(2, 6);
// Save the link in the lex.json file fs.readFile('lex.json', (err, data) => { if (err) { console.error(err); res.status(500).send('Error generating link'); return; }
const links = JSON.parse(data);
links[linkId] = {
destination: 'http://localhost:4000/',
expires: Date.now() + 1000 * 60 * 5 // expires in 5 minutes
};
fs.writeFile('lex.json', JSON.stringify(links), (err) => {
if (err) {
console.error(err);
res.status(500).send('Error generating link');
return;
}
// Send the link back to the client
res.send(`http://localhost:3000/${linkId}`);
});
}); });
app.get('/:linkId', (req, res) => {
fs.readFile('lex.json', (err, data) => {
if (err) { console.error(err); res.status(500).send('Error retrieving link');
return;
}
const links = JSON.parse(data);
const link = links[req.params.linkId];
if (!link) {
res.status(404).send('Link not found');
return;
}
// Check if the link has expired
if (link.expires < Date.now()) {
res.status(410).send('Link has expired');
return;
}
// Redirect to the destination
res.redirect(link.destination);
}); });
app.listen(3000, () => { console.log('Server listening on port 3000'); });
//GEERTOOOO
const clients = {};
const getUniqueID = () => { const s4 = () => Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
return s4() + s4() + '-' + s4(); }
wsServer.on('request', (request) => { var userID = getUniqueID();
const connection = request.accept(null, request.origin); clients[userID] = connection;
connection.on('message', (message) => {
if (message.type === 'utf8') {
for(var key in clients) {
if (clients[key] !== clients[userID]) {
clients[key].sendUTF(message.utf8Data);
console.log(`Sent Message to: ${clients[key]}`);
}
}
}
}) })
Note: the express server is on port 3000 and the websocket server runs on port 8000.
I,ve tried just changing the port to same thing but i get an error when trying to use the websocket server for messages.
THE PURPOSE OF ALL THIS IS JUST TO MAKE THE WEBSOCKET CONNECTION AND EXPRESS CONNECCTION SECURE SO MY APPS (with letsencrypt ssl) can connect to the servers
It is not possible to create two separate server instances, both listening on the same port. But, specifically for a webSocket, you can share one server instance between Express and the webSocket server code. This is possible because a webSocket connection always starts with an http request (thus it can be listened for using your Express http server. And, because these http requests that initiate a webSocket all contain identifying headers they can be separated out from the regular http requests for Express by looking at the headers. The webSocket server code already knows how to do that for you.
To do that, first capture the Express server instance:
const server = app.listen(3000, () => { console.log('Server listening on port 3000'); });
Then, use that server instance when you create your webSocket server.
const wsServer = new webSocketServer({ httpServer: server });
Then, remove this code because you don't want to create yet another http server instance for the webSocket server:
const server = http.createServer();
server.listen(webSocketServerPort);
console.log('Listening on port 8000');

Client getting 'Bad Request' response from server

I'm using nodejs net library.
Locally everything works fine, I can connect to server with client, send data to server and I'm getting response.
But once deployed on server (with traefik), when I run client-app.js I keep getting:
Connected
Received: HTTP/1.1 400 Bad Request
Content-Type: text/plain; charset=utf-8
Connection: close
400 Bad Request
Connection closed
Traefik is configured to redirect every request that comes to "my-address.com" to 1337 port on docker container (in which runs server-app.js).
Here's my code:
server-app.js:
const net = require('net');
const PORT = 1337;
const HOST = '0.0.0.0';
var server = net.createServer(function(socket) {
socket.write('Echo server\r\n');
//socket.pipe(socket);
socket.on('data', (data) => {
console.log('DATA RECEIVED')
socket.write('GOT DATA', data)
});
});
server.on('connection', (socket)=> {
console.log('Connection from: ', socket.remoteAddress)
});
server.listen(PORT, HOST, () => {
console.log(`SERVER IS UP. PORT ${PORT}`)
})
client-app.js:
const net = require('net');
const PORT = 443;
const HOST = 'my-addres.com';
var client = new net.Socket();
console.dir(client.connect)
client.connect({port: PORT, host: HOST}, function() {
console.log('Connected');
client.write('Hello, server! Love, Client.\n');
var counter = 1;
setInterval(()=>{client.write(`Data nr ${counter}\n`); counter += 1}, 1000)
});
client.on('data', function(data) {
console.log('Received: ' + data);
//client.destroy(); // kill client after server's response
});
client.on('close', function() {
console.log('Connection closed');
});
Your client and server don't speak the HTTP protocol but do their own application protocol on top of TCP. But it looks like you've configured Traefik to be a HTTP router since what you receive is a HTTP response. Since you don't use HTTP you should not use a HTTP but a TCP router instead.

How to handle Node.js http server timeout event?

I have a HTTP server that will always result in HTTP timeout, e.g.
const server = http.createServer((req, res) => {
setTimeout(() => {
res.writeHead(200);
res.write('OK');
res.end();
}, 2000);
});
server.setTimeout(1000);
server.on('timeout', (socket) => {
// How to produce a custom HTTP response here?
});
HTTP server "timeout" event is emitted with socket reference. How do I use socket to encode HTTP response?
I know that I can stitch the response myself at a low-level, e.g.
server.on('timeout', (socket) => {
socket.write([
'HTTP/1.1 408 Request Timeout',
'Connection: close'
].join('\n') + '\n\n');
socket.end();
});
But is there a way to use the HTTP response interface, i.e. writeHead/ write/ end?
You could use the setTimeout function on the response object. Consider this simple example:
const http = require('http');
const port = 3000;
const requestHandler = (req, res) => {
res.setTimeout(Math.random() * 2500, () => {
res.writeHead(408);
res.end();
});
setTimeout(() => {
if (res.headersSent) {
return;
}
res.writeHead(200);
res.write('OK');
res.end();
}, 2000);
};
const server = http.createServer(requestHandler);
server.listen(port, (err) => {
if (err) {
return console.log('an error happened', err)
}
console.log(`server is listening on ${port}`)
});
If you call localhost:3000 in your web browser you'll now either see 200 OK or a 408 error. Note that you'll need to handle already sent headers if the random timeout was less than 2000 ms.

http.Server's 'connect' event is never called

I create a simple http server from which I want do transfer some bytes of data over socket. So i am listening to 'connect' event of the server. But it is never called?
here is my code.
var http = require('http');
var server = http.createServer(function(req, res) {
res.setHeader('Content-type', 'text/html');
res.end('<h3>Yeah! you are connected on ' + Date() + '</h3>');
console.log('User connected');
});
server.on('connect', function(req, socket, head) {
//var addr = socket.remoteAddress;
console.log('IP - ');
});
server.listen(8000);
For connect event, when the server is running, need to make a request to a tunneling proxy.
Replace your server.listen(8000); with this:
server.listen(8000, '127.0.0.1', () => {
// make a request to a tunneling proxy
const options = {
port: 8000,
hostname: '127.0.0.1',
method: 'CONNECT',
path: 'www.google.com:80'
};
const req = http.request(options);
req.end();
});

Tunnel between servers that supports any port

I'm trying to create a tunnel using Node.js that will allow me to access Server X from Server Y. Server X is connected to a router that isn't port forwarded and I won't know the IP of Server X until it connects, which means that Server X has to open a socket to Server Y and not the other way round.
I've successfully created a version of this using socket.io. Server X opens a socket to server Y, the user can then access Server Y in a web browser and Server Y proxies the requests down the socket to Server X.
What I would like to do is allow access to any kind of port on Server X, and forward not just web requests but requests of any kind. For example, I'd like to allow forwarding of SSH so I can access SSH on Server X through Server Y (doesn't have to be port 22). localtunnel.me is an existing service which is an exact example of what I want to achieve.
Are there any libraries that could help me achieve this, or can I build it from the ground up quite easily? I built the web request tunnel easily, perhaps it can be adapted to support not just web traffic? I've attached the code to my existing web tunnel below.
Server X (connects to Server Y on port 3001, receives requests for data and sends it back:
var socket = require('socket.io-client')('http://localhost:3001');
socket.on('connect', function(){
console.log('Connected');
// Register the event for request of data
socket.on('request', function(data){
// Get the path
var options = {
host: 'localhost',
port: 3000,
path: data.path,
method: data.method
};
var request = http.get(options, function(resp){
resp.on('data', function(chunk){
socket.emit('response', { html: chunk });
// Probably need to fix this for file transfers. Use resp.on('end'
});
}).on("error", function(e){
console.log("Got error: " + e.message);
});
//Write our post data to the request
request.write(data.data);
//End the request.
request.end();
});
socket.on('disconnect', function(){});
});
Server Y (listens on port 3001 to connect to Server X, and listens on port 3002 for requests from user in web browser to forward to Server X:
app.listen(3001);
var rwPortalSocket;
function handler (req, res) {
fs.readFile(__dirname + '/index.html',
function (err, data) {
if (err) {
res.writeHead(500);
return res.end('Error loading index.html');
}
res.writeHead(200);
res.end(data);
});
}
io.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
// Save the socket object
rwPortalSocket = socket;
});
console.log('Data channel server running at http://127.0.0.1:3001/');
// Create web server
var http = require('http');
var qs = require('querystring');
http.createServer(function (req, res) {
// Send a request
rwPortalSocket.emit('request', { path: req.url, method: req.method });
// When we get a response
rwPortalSocket.on('response', function (responseData) {
res.writeHead(200);
res.end(responseData.html);
});
}).listen(3002, '127.0.0.1');
console.log('Web server running at http://127.0.0.1:3002/');
EDIT
I've now updated my code so that should support any TCP port or packet type. The code works fine when I tell net.connect to connect to a web server, but when I tell it to connect an SSH server, my SSH client complains with Protocol error: expected packet type 31, got 20
I've added an example of my new code connecting to an SSH server below.
Server X (connects to Server Y on port 3001, receives requests for data and sends it back:
var socket = require('socket.io-client')('http://localhost:3001');
socket.on('connect', function(){
console.log('Connected');
// Connect to 22
var buff = "";
var connected = false;
var net = require('net');
var client = net.connect({host: 'myserver.com', port: 22}, function() { //'connect' listener
connected = true;
console.log('Connected to 22');
});
// Register the event for request of data
socket.on('request', function(data){
if (!connected)
{
client = net.connect({host: 'myserver.com', port: 22}, function() { //'connect' listener
connected = true;
console.log('Connected to 22');
client.write(data.data);
});
}
else
{
client.write(data.data);
}
client.setMaxListeners(0);
// When data comes back to this service, we send it on to the other server
client.on('data', function(data) {
//console.log(data.toString());
console.log('Server sent back: ' + data.toString());
if (connected)
{
socket.emit('response', { data: data });
} else {
buff += d.toString();
}
});
client.on('end', function() {
console.log('Disconnected from 22');
connected = false;
});
client.on('error', function(e) {
console.log(e);
});
console.log('Client sent: ' + data.data);
});
socket.on('disconnect', function(){});
});
Server Y (listens on port 3001 to connect to Server X, and listens on port 3002 for requests from user in SSH Client (terminal) to forward to Server X:
app.listen(3001);
var rwPortalSocket;
function handler (req, res) {
fs.readFile(__dirname + '/index.html',
function (err, data) {
if (err) {
res.writeHead(500);
return res.end('Error loading index.html');
}
res.writeHead(200);
res.end(data);
});
}
io.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
// Save the socket object
rwPortalSocket = socket;
});
console.log('Data channel server running at http://127.0.0.1:3001/');
// Listen for tunnel requests
net = require('net');
var server = net.createServer(function(s) { //'connection' listener
s.on('end', function() {
console.log('server disconnected');
});
s.on('data', function (d) {
rwPortalSocket.emit('request', { data: d });
});
s.on('error', function(e) {
console.log(e);
});
s.setMaxListeners(0);
// When we get a response
rwPortalSocket.on('response', function (d) {
s.write(d.data);
});
});
server.listen(3002, function() { //'listening' listener
console.log('server bound');
});
console.log('Web server running at http://127.0.0.1:3002/');
If the "connections" to Server X would all be TCP-based, you could have an SSH server running on both ends. Server X would then connect to Server Y to only forward some port on Server Y that would point to the SSH server running on Server X. Then you could use a node module like ssh2 to connect to any port on Server X.
Another option for dynamic forwarding would be to set up a socks proxy as described in this answer. From there you could use a socks client module from npm, such as socks5-client.
If instead you have a fixed set of ports that you want have available, you could simplify the above solutions by just having an SSH server on Server Y and Server X connects and creates a port forward for each port you want to have available.
Here is an example of another option: connecting to Server X from Server Y via SSH and opening up connections on Server X using the SSH connection (via ssh2).

Resources