http to https node proxy - proxy

I would like to know the easiest way to set up a proxy where I can make HTTP requests in (i.e.) localhost:8011 and the proxy makes a HTTPS request in localhost:443 (the HTTPS answer from the server should be translated to HTTP by the proxy as well)
I'm using node.js
I've tried http-proxy like this:
var httpProxy = require('http-proxy');
var options = {
changeOrigin: true,
target: {
https: true
}
}
httpProxy.createServer(443, 'localhost', options).listen(8011);
I have also tried this:
httpProxy.createProxyServer({
target: {
host:'https://development.beigebracht.com',
rejectUnauthorized: false,
https: true,
}
}).listen(port);
But when I'm trying to connect I'm getting this error
/Users/adrian/Development/beigebracht-v2/app/webroot/node_modules/http-proxy/lib/http-proxy/passes/web-incoming.js:103
var proxyReq = (options.target.protocol === 'https:' ? https : http).reque
^
TypeError: Cannot read property 'protocol' of undefined
I would like to do it with node, but, other solutions can be valid.
(The proxy will be used in localhost just with testing purposes so security is not a problem)

I needed a HTTP->HTTPS node proxy for unit testing. What I ended up doing was creating the HTTP proxy and then have it listen for and handle the connect event. When the server receives the CONNECT request, it sets up a tunnel to the HTTPS target URL and forwards all packets from the client socket to the target socket and vice versa.
Sample code:
var httpProxy = require('http-proxy');
var net = require('net');
var url = require('url');
var options = {
host: 'localhost',
port: 3002
};
var proxy = httpProxy.createProxyServer();
proxy.http = http.createServer(function(req, res) {
var target = url.parse(req.url);
// The `path` attribute would cause problems later.
target.path = undefined;
proxy.web(req, res, {
target: target
});
}).listen(options.port, options.host);
// This allows the HTTP proxy server to handle CONNECT requests.
proxy.http.on('connect', function connectTunnel(req, cltSocket, head) {
// Bind local address of proxy server.
var srvSocket = new net.Socket({
handle: net._createServerHandle(options.host)
});
// Connect to an origin server.
var srvUrl = url.parse('http://' + req.url);
srvSocket.connect(srvUrl.port, srvUrl.hostname, function() {
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);
});
});

Related

socket.io WebSocket connection failed

I am using socket.io to connect to a different domain, and it can successfully connect using polling, however when attempting to connect using websockets gets the error "WebSocket connection to 'wss://XXXXX' failed".
After observing the network activity the server seems to indicate that it is capable of upgrading to a websocket connection (although I won't claim to be an expert in understanding these requests), but isn't able to do so:
I'm just trying to produce a minimal viable product right now so here is my node.js server code:
let http = require('http');
let https = require('https');
let fs = require('fs');
let express = require('express');
const privateKey = fs.readFileSync('XXXXXXXXX', 'utf8');
const certificate = fs.readFileSync('XXXXXXXXX', 'utf8');
const ca = fs.readFileSync('XXXXXXXXX', 'utf8');
const options = {
key: privateKey,
cert: certificate,
ca: ca
};
let app = express();
let httpsServer = https.createServer(options,app);
let io = require('socket.io')(httpsServer, {
cors: {
origin: true
}
});
httpsServer.listen(443);
console.log('starting');
io.sockets.on('connection', (socket) => {
console.log("something is happening right now")
socket.on("salutations", data => {
console.log(`you are now connected via ${socket.conn.transport.name}`);
socket.emit("greetings", "I am the socket confirming that we are now connected");
});
});
Client-side JavaScript:
const socket = io("https://XXXXXXX");
console.log(socket);
socket.on("connect", () => {
console.log("now connected");
socket.on("message", data => {
console.log(data);
});
socket.on("greetings", (elem) => {
console.log(elem);
});
});
let h1 = document.querySelector('h1');
h1.addEventListener('click',()=>{
console.log("I am now doing something");
socket.emit("salutations", "Hello!");
})
The only suggestion in the official documentation for this issue isn't relevant because I'm not using a proxy, and other suggested fixes result in no connection at all (presumably because they prevent it from falling back to polling)
EDIT: also if it helps narrow down the problem, when querying my server using https://www.piesocket.com/websocket-tester it results in "Connection failed, see your browser's developer console for reason and error code"

Getting "connect_error due to xhr poll error" while connecting socket server

I am trying to connect socket.io client which inside react app to the socket.io server but i am getting xhr poll error. I am unable to figure out what is going wrong? client & server code is as follow:
import io from 'socket.io-client';
const socket = io("ws://loacalhost:5000");
socket.on("connect_error", (err) => {
console.log(`connect_error due to ${err.message}`);
});
const express = require('express');
const app = express();
app.use(require('cors')());
const http = require('http');
const server = http.createServer(app);
const io = require("socket.io")(server, {
rejectUnauthorized: false,
cors: {
origin: "http://localhost:3000",
methods: ["GET", "POST"]
}
})
io.on("connection", (socket) => {
console.log(socket.id)
})
server.listen(5000, () => {
console.log('Server is listening on Port 5000');
});
Everything is ok in server file as well as everything is ok in client file except there is syntax mistake in client code i.e.
const socket = io("ws://loacalhost:5000");
replaced with:
const socket = io("ws://localhost:5000");
then it is worked fine, successfully connected to server
Your localhost spelling is incorrect.
const socket = io("ws://loacalhost:5000");
Replaced with
const socket = io("ws://localhost:5000");

Socket IO forbidden 403

I have a simple socket.io app and it works just fine on local and also it's installed successfully on AWS server using plesk admin dashboard but when I connect to the app I always get forbidden {"code":4,"message":"Forbidden"} .. the entry point seems to work great http://messages.entermeme.com .. any idea what could be wrong with it ?
Frontend code
import io from 'socket.io-client'
const socket = io('https://messages.entermeme.com', {
transports: ['polling'],
})
socket.emit('SUBSCRIBE')
Backend code
const cors = require('cors')
const app = require('express')()
const server = require('http').Server(app)
const io = require('socket.io')(server)
server.listen(9000)
app.use(cors())
io.set('transports', [
'polling'
])
io.origins([
'http://localhost:8000',
'https://entermeme.com',
])
io.on('connection', (socket) => {
socket.on('SUBSCRIBE', () => {
//
})
})
had a similar issue but when using nginx. So in case you still need some help:
In the end it turned out to be the URL I specified as socket origins. I didn't specify the port since the origin for me was also running on port 80 (443 for SSL) like in your example above:
io.origins([
'http://localhost:8000',
'https://entermeme.com', // <--- No port specified
])
I updated my config and added the port. So for you it would be:
io.origins([
'http://localhost:8000',
'https://entermeme.com:80', // <--- With port (or 443 for SSL)
])

Error using socket.io along with webpack-dev-server

Quick question guys, I am trying to use webpack-dev-server with socketio, but after trying different things, i figured both of the clients are listening to the same port '3000' and I end up with some kind of handshake error that goes away if I dont use webpack-dev-server on the same port.. here is my server config
const PORT = process.env.PORT || 3000;
new WebpackDevServer(webpack(config), {
publicPath: config.output.publicPath,
hot: true,
historyApiFallback: true,
setup(app) {
const server = require('http').Server(app);
let onlineUsers = 0;
const io = require('socket.io')(server);
io.on('connection', (socket) => {
console.log(`A client is connected:${socket.id}`);
onlineUsers++;
io.sockets.emit('onlineUsers', {
onlineUsers
});
});
server.listen(3000, () => {
console.log('listening on *:3000');
});
}
}).listen(PORT, 'localhost', (err) => {
if (err) {
console.log(err);
}
console.log(`Listening at localhost: ${PORT}`);
});
and webpack config
entry: [
'webpack-dev-server/client?http://localhost:3000',
'webpack/hot/only-dev-server',
'react-hot-loader/patch',
'./src/app.js'
],
these are the error(s)
WebSocket connection to 'ws://localhost:3000/sockjs-
node/608/jsbr0a0r/websocket' failed: Connection closed
before receiving a handshake response
T http://localhost:3000/sockjs-node/225/qvolyk2n/eventsource
iframe.js?ea3f:102 GET http://localhost:3000/sockjs-node/iframe.html 404 (Not Found)
createIframe # iframe.js?ea3f:102
IframeTransport # iframe.js?7dcb:42
IframeWrapTransport # iframe-wrap.js?7e29:11
SockJS._connect # main.js?45b8:219
SockJS._transportClose # main.js?45b8:299
g # emitter.js?927b:30
EventEmitter.emit # emitter.js?927b:50
(anonymous) # sender-receiver.js?620a:28
g # emitter.js?927b:30
EventEmitter.emit # emitter.js?927b:50
(anonymous) # polling.js?97d6:41
g # emitter.js?927b:30
EventEmitter.emit # emitter.js?927b:50
(anonymous) # eventsource.js?d407:58
VM776:66[HMR] Waiting for update signal from WDS...
VM1157:49Warning: [react-router] Location "/sockjs-node/225/ucoowxum/htmlfile?c=_jp.alfvbqm" did not match any routes
I was trying is to proxy the request to a different port
proxy: {
"http://localhost:3000": "http://localhost:4000"
}
and then listen to that in the configurations
entry: [
'webpack-dev-server/client?http://localhost:4000',
'webpack/hot/only-dev-server',
'react-hot-loader/patch',
'./src/app.js'
],
but I don't know if that is the way to go, anyone know how to fix this?
The issue is your proxy is not correctly configured. By default when you call the socket.io constructor, this line
const io = require('socket.io')(server);
All socket.io requests will go to your webpack dev server http://localhost:3000/socket.io (note the end of the URL - important) in your case. You want to proxy those requests to http://localhost:4000/socket.io, not every request that hits http://localhost:3000. You're also missing the ws: true line. So actually the correct configuration is the following:
proxy: {
'/api': {
target: 'http://localhost:4000',
pathRewrite: {"^/api": ""}
},
'/socket.io': {
target: 'http://localhost:4000',
ws: true
}
}
You don't need the first '/api' part if you don't have have a backend API that is listening to other requests. I'm just assuming you do. It's possible you just have all sockets in which case you can ignore that line. In most cases, people will have sockets and other http requests.
Hope this helps anyone trying to set up webpack-dev-server and socket.io with a proxy.
just to be thorough, here's the full nodejs implementation of it.
nodejs:
const http = require("http").createServer(app);
const io = require('socket.io')(http);
io.set('transports', ['websocket']);
http.listen(3002, () => console.log(`socket: http://${ip.address()}:3002`, "Time:", moment(new Date().getTime()).format("DD日 h:mm:ss")));
frontend:
var server = "/";
var connectionOptions = {
"force new connection": true,
"reconnectionAttempts": "Infinity", //avoid having user reconnect manually in order to prevent dead clients after a server restart
"timeout": 10000, //before connect_error and connect_timeout are emitted.
"transports": ["websocket"]
};
store.state.socket = io(server, connectionOptions);
store.state.socket.on('connect', () => {
console.log('socket connected ----');
});
webpack:
const target = "http://" + "localhost" + ":" + "3001";
const socket = "http://" + "localhost" + ":" + "3002";
module.exports = {
devServer: {
https: true,
key: fs.readFileSync('./src/localhostcert/key.pem'),
cert: fs.readFileSync('./src/localhostcert/cert.pem'),
host: 'localhost',
hot: true,
compress: true,
port: 8080,
proxy: {
"/socket.io": {
target: socket,
ws: true
}
}
}
}

Socket.io connection url?

I have the current setup:
Nodejs Proxy (running http-reverse-proxy) running on port 80.
Rails server running on port 3000
Nodejs web server running on port 8888
So any request starting with /nodejs/ will be redirected to nodejs web server on 8888.
Anything else will be redirected to the rails server on port 3000.
Currently Socket.io requires a connection url for io.connect.
Note that /nodejs/socket.io/socket.io.js is valid and returns the required socket.io client js library.
However, I am not able to specify connection_url to /nodejs/ on my server.
I have tried http://myapp.com/nodejs and other variants but I am still getting a 404 error with the following url http://myapp/socket.io/1/?t=1331851089106
Is it possible to tell io.connect to prefix each connection url with /nodejs/ ?
As of Socket.io version 1, resource has been replaced by path. Use :
var socket = io('http://localhost', {path: '/nodejs/socket.io'});
See: http://blog.seafuj.com/migrating-to-socketio-1-0
you can specify resource like this:
var socket = io.connect('http://localhost', {resource: 'nodejs'});
by default resource = "socket.io"
If you are using express with nodejs:
Server side:
var io = require('socket.io')(server, {path: '/octagon/socket.io'});
then
io.on('connection', function(socket) {
console.log('a user connected, id ' + socket.id);
socket.on('disconnect', function() {
console.log('a user disconnected, id ' + socket.id);
})
})
socket.on('publish message ' + clientId, function(msg) {
console.log('got message')
})
Client side:
var socket = io('https://dev.octagon.com:8443', {path: '/octagon/socket.io'})
then
socket.emit('publish message ' + clientId, msg)
I use below approach to achieve this goal:
client side:
var socket = io.connect('http://localhost:8183/?clientId='+clientId,{"force new connection":true});
server side:
var io = require('socket.io').listen(server);
io.sockets.on('connection', function(socket) {
console.log("url"+socket.handshake.url);
clientId=socket.handshake.query.clientId;
console.log("connected clientId:"+clientId);
});
reference:https://github.com/LearnBoost/socket.io/wiki/Authorizing#global-authorization
If you are serving your app with express, then maybe you can check this out. Remember express uses http to serve your application.
const express = require('express'),
http = require('http'),
socketIo = require('socket.io'),
app = express()
var server = http.createServer(app);
var io = socketIo(server);
io.on('connection', (socket)=>{
// run your code here
})
server.listen(process.env.PORT, ()=> {
console.log('chat-app inintated succesfully')
})

Resources