I have a websocket client-server application. Here's client's simplified code:
const HOST = "wss://localhost:8000";
const SUB_PROTOCOL= "sub-protocol";
var websocket = new WebSocket(HOST, SUB_PROTOCOL);
websocket.onopen = function(evt) { ... };
websocket.onclose = function(evt) { ... };
websocket.onerror = function(evt) { ... };
websocket.onmessage = function(evt) { ... };
And here's server:
const PORT = 8000;
const SUBPROTOCOL = 'sub-protocol';
var WebSocketServer = require('websocket').server;
var https = require('https');
var fs = require('fs');
// Private key and certification (self-signed for now)
var options = {
key: fs.readFileSync('cert/server.key'),
cert: fs.readFileSync('cert/server.crt')
};
var server = https.createServer(options, function(request, response) {
console.log((new Date()) + ' Received HTTP(S) request for ' + request.url);
response.writeHead(404);
response.end();
});
// bind server object to listen to PORT number
server.listen(PORT, function() {
console.log((new Date()) + ' Server is listening on port ' + PORT);
});
wsServer = new WebSocketServer({
httpServer: server,
// You should not use autoAcceptConnections for production
// applications, as it defeats all standard cross-origin protection
// facilities built into the protocol and the browser. You should
// *always* verify the connection's origin and decide whether or not
// to accept it.
autoAcceptConnections: false
});
function originIsAllowed(origin) {
// put logic here to detect whether the specified origin is allowed.
return true;
}
// If autoAcceptConnections is set to false, a request event will be emitted
// by the server whenever a new WebSocket request is made
wsServer.on('request', function(request) {
if (!originIsAllowed(request.origin)) {
// Make sure we only accept requests from an allowed origin
request.reject();
console.log((new Date()) + ' Connection from origin ' + request.origin + ' rejected.');
return;
}
// accepts connection and return socket for this connection
var connection = request.accept(SUB_PROTOCOL, request.origin);
console.log((new Date()) + ' Connection accepted.');
// when message is received
connection.on('message', function(message) {
// echo
connection.send(connection, message.utf8Data);
});
connection.on('close', function(reasonCode, description) {
console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
});
});
Both client and server works as expected even with some HTTPS pages (tested on Twitter, mail.ru,). But for some reason doesn't for example with Facebook or GitHub.
In JavaScript console I get this:
Exception { message: "", result: 2153644038, name: "", filename: "", lineNumber: 0, columnNumber: 0, inner: null, data: null }
Then huge stack trace follows: pasted it here
and at the end:
Content Security Policy: The page's settings blocked the loading of a resource at wss://localhost:8000/ ("connect-src https://github.com:443 https://ghconduit.com:25035 https://live.github.com:443 https://uploads.github.com:443 https://s3.amazonaws.com:443").
I don't see how does these page differ from pages, which works. I'd also like to point out, that these pages works in Chrome.
(tested in Firefox 31)
The pages where the WebSocket connection fails have a Content-Security-Policy header with the connect-src directive set to only allow connections to a set of whitelisted domains. This means that all connections from that page to any non-whitelisted domain will fail.
Its not clear how you're running this code. It seems possible that Chrome allows extensions to bypass that header restriction while Firefox does not, or something to that effect.
Related
I have VPS with LAMP. I have free signed SSL certificate from Startssl.com (ssl certificate working correctly)
With http:// protocol I can connect to ws://chat.example.com:1337/some-variable but when I replace protocol http:// to https:// then I can't connect to wss://chat.example.com:1337/some-variable
When I try to connect to wss:// I'm getting error Error in connection establishment: net::ERR_CONNECTION_CLOSED
Why?
// http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/
"use strict";
// Optional. You will see this name in eg. 'ps' or 'top' command
process.title = 'node-chat';
// Port where we'll run the websocket server
var webSocketsServerPort = 1337;
// websocket and http servers
var webSocketServer = require('websocket').server;
var http = require('http');
var $ = require("jquery");
/**
* HTTP server
*/
var server = http.createServer(function(request, response) {
// Not important for us. We're writing WebSocket server, not HTTP server
});
server.listen(webSocketsServerPort, function() {
console.log((new Date()) + " Server is listening on port " + webSocketsServerPort);
});
/**
* WebSocket server
*/
var wsServer = new webSocketServer({
// WebSocket server is tied to a HTTP server. WebSocket request is just
// an enhanced HTTP request. For more info http://tools.ietf.org/html/rfc6455#page-6
httpServer: server
});
EDIT
I have source from http://ahoj.io/nodejs-and-websocket-simple-chat-tutorial
To critique my answer better, as the last one was a mistake and I didn't mean to submit it until after I finished digging, try this:
// Private key and certification
var options = {
key: fs.readFileSync('cert/server.key'),
cert: fs.readFileSync('cert/server.crt')
};
var server = https.createServer(options, function(request, response) {
console.log((new Date()) + ' Received HTTP(S) request for ' + request.url);
}
I am trying to have two different Node processes (using Cluster) try to become servers to a Port. However, whenever the second process gets to the port, it doesn't detect that the port is being used.
I suspect the reason why they are not detecting if the port is open or not is due to the nature of callbacks (I'm detecting if the port is used or not using the portInUse function, so it is fetched asynchronously, and might cause some type of conflict later on).
Here is the code:
var cluster = require('cluster');
var net = require('net');
var PORT = 1337;
var list = {};
var portIsBeingUsed = false;
// Variable that detects if the port is in use.
var portInUse = function(port, callback) {
var server = net.createServer(function(socket) {
socket.write('Echo server\r\n');
socket.pipe(socket);
});
server.listen(port, 'localhost');
server.on('error', function (e) {
callback(true);
});
server.on('listening', function (e) {
server.close();
callback(false);
});
};
if (cluster.isMaster) {
for (var i = 0; i < 2; i++) {
cluster.fork();
}
Object.keys(cluster.workers).forEach(function(id) {
console.log("I am running with ID : "+ cluster.workers[id].process.pid);
list[cluster.workers[id].process.pid] = 0;
});
cluster.on('exit', function(worker, code, signal) {
console.log('worker ' + worker.process.pid + ' died');
});
} else { // Rest of the logic with all Processes goes here.
// Get the Process ID of the current process in execution.
var pid = cluster.worker.process.pid;
console.log("This is process " + pid + " working now.\n");
// Verify if Port is being used.
portInUse(PORT, function(returnValue) {
if(returnValue) { // Become a Client to the Server
console.log("port " + PORT + " is being used.\n\n");
becomeClient(pid);
} else { // Become a Server
console.log("port" + PORT + " is not being used.\n\n");
becomeServer(pid);
}
});
}
function becomeServer(pid) {
var server = list[pid];
server = net.createServer(function (socket) {
socket.write('Hello Server 1\r\n');
socket.end("hello");
console.log("Someone connected to Server 1. \n");
socket.pipe(socket);
});
server.listen(PORT, function(){
console.log("Process " + pid + " has become the Server on Port " + PORT);
});
server.on("error", function() {
console.log("there was an error on Process " + pid);
console.log("this error was becoming a Server.");
});
}
function becomeClient(pid) {
var client = list[pid];
client = net.connect({port: PORT}, function() {
list[pid].write("I am connected to the port and my pid is " + pid);
});
client.on('data', function(data) {
console.log(data.toString());
list[pid].end();
});
client.on('end', function() {
console.log('disconnected from server');
});
}
And here is the output:
So the first process (In this case Process 9120) becomes the server on port 1337, but then the second process doesn't detect that the port is being used and somehow becomes the server as well (I would expect an EADDRINUSE here, not sure why it isn't showing any errors).
Any help or clarification as to why this isn't working would be greatly appreciated.
Thanks,
This is expected behavior and it is how the cluster module works (by default). It's what allows incoming requests to the same port to be easily distributed among the available workers.
A large part of the point of cluster involves port sharing, so that you can have multiple workers take turns serving requests. The worker processes just request a port from the master, which actually opens the port, and then the master hands requests back to any workers that have requested that port.
Related to this question Browser with JavaScript TCP Client I asked whether I can connect from a browser to a tcp server. I found out that it won't work so I asked for another solution. '0101' provided me to built up two servers. One tcp server for a c++ application that connects to and one websockets server that receives data from the browser. I have originally built up each one of them, but I don't know how to connect them so I can receive data from the browser in the c++ application.
Here is the websockets-server:
var ClientListe = {};
// Anzahl der Verbundenen Clients
var ClientAnzahl=0;
// Websocket-Server
var WebSocketServer = require('ws').Server
var wss = new WebSocketServer({host: '127.0.0.1',port: 80});
wss.on('connection', function(ws)
{
// Client-Anzahl hochzählen
ClientAnzahl++;
// Client-Verbindung mit in die Client-Liste Aufnehmen
ws['AUTH'] = ClientAnzahl;
ClientListe[ws['AUTH']] = ws;
// Ausgabe
console.log('client '+ClientAnzahl+' verbunden...');
ws.on('message', function(message)
{
console.log('von Client empfangen: ' + message);
for(client in ClientListe)
{
ClientListe[client].send('von Server empfangen: ' + message);
}
});
ws.on('close', function()
{
// Client aus der ClientListe Löschen
delete ClientListe[ws['AUTH']];
// Nachricht der Trennung an die Console ausgeben
console.log('Client '+ ws['AUTH'] +' getrennt.');
});
});
and here is the tcp server:
// Load the TCP Library
net = require('net');
// Keep track of the chat clients
var clients = [];
// Start a TCP Server
net.createServer(function (socket) {
// Identify this client
socket.name = socket.remoteAddress + ":" + socket.remotePort;
// Put this new client in the list
clients.push(socket);
// Send a nice welcome message and announce
socket.write("Welcome " + socket.name + "\n");
broadcast(socket.name + " joined the server\n", socket);
// Handle incoming messages from clients.
socket.on('data', function (data) {
broadcast(socket.name + " message: " + data, socket);
});
// Remove the client from the list when it leaves
socket.on('end', function () {
clients.splice(clients.indexOf(socket), 1);
broadcast(socket.name + " left the server.\n");
});
// Send a message to all clients
function broadcast(message, sender) {
clients.forEach(function (client) {
// Don't want to send it to sender
if (client === sender) return;
client.write(message);
});
// Log it to the server output too
process.stdout.write(message)
}
}).listen(80);
// Put a friendly message on the terminal of the server.
console.log("TCP Server running at localhost port 80\n");
Both are copied out of the internet for testing some cases
Create a TCP server (NodeJS example)
var net = require("net");
var server = net.createServer(function(c) { //'connection' listener
console.log('server connected');
c.on('end', function() {
console.log('server disconnected');
});
c.write('hello\r\n');
c.pipe(c);
});
server.listen(8124, function() { //'listening' listener
console.log('server bound');
});
Then in the same file (optionally of course) create a WS server with different port number
var WebSocketServer = require("ws").Server;
var wss = new WebSocketServer({
port: 8080
});
wss.on("connection", function(ws) {
console.log("CONNECTED");
// ws.on("message"), ws.on("close"), ws.on("error")
});
Now you should have two servers, one for regular sockets and another one for WebSockets.
// As I mentioned in the previous question and Pete as well, it is a lot better to use WebSockets in C++ as well instead of creating two servers...
Drop the TCP server and make the C++ client connect to the websockets server instead. You'll need to implement the websockets protocol on top of your TCP connection at the C++ end (all you really need is a bit of pre-amble to negotiate the websocket). You have problems here with both servers trying to use port 80.
By the way, you should also consider using HTTPS for the websocket instead of HTTP since it avoids problems with proxy traversal. But get the HTTP case working first as this will be more complicated to implement on the C++ end.
I have a node js server, and a html/javascript client.
I simply want to allow the client to send a json-string to the node.js server, the server process's that string and returns a result string back to the client.
I started by setting up the html-client to call like so :
var msg =
{
type: "message",
text: "Hello"
};
function CallWebSocket()
{
var socket = new WebSocket("ws://127.0.0.1:8080","test");
socket.onopen = function (event)
{
alert(JSON.stringify(msg));
socket.send(JSON.stringify(msg));
};
socket.onmessage = function(event)
{
alert(event.data);
}
}
and node.js :
var net = require('net');
var server = net.createServer(function(socket)
{
// do what you need
socket.setEncoding("utf8");
socket.on('data', function(data)
{
var jsonData = JSON.parse(data);
socket.write(jsonData.text);
socket.end();
process.exit(0);
});
});
server.listen(8080);
but on the server I get this error :
undefined:1
``GET / HTTP/1.1
^
SyntaxError: Unexpected token G
at Object.parse (native)
at Socket.<anonymous> (/home/jay/projects/nodejs/test/json-server.js:8:23)
at Socket.EventEmitter.emit (events.js:95:17)
at Socket.<anonymous> (_stream_readable.js:746:14)
at Socket.EventEmitter.emit (events.js:92:17)
at emitReadable_ (_stream_readable.js:408:10)
at emitReadable (_stream_readable.js:404:5)
at readableAddChunk (_stream_readable.js:165:9)
at Socket.Readable.push (_stream_readable.js:127:10)
at TCP.onread (net.js:526:21)
Any help is much appreciated.
UPDATE
The updated server code :
var WebSocketServer = require('websocket').server;
var http = require('http');
var server = http.createServer(function(request, response) {
console.log((new Date()) + ' Received request for ' + request.url);
response.writeHead(404);
response.end();
});
server.listen(8080, function() {
console.log((new Date()) + ' Server is listening on port 8080');
});
wsServer = new WebSocketServer({
httpServer: server,
// You should not use autoAcceptConnections for production
// applications, as it defeats all standard cross-origin protection
// facilities built into the protocol and the browser. You should
// *always* verify the connection's origin and decide whether or not
// to accept it.
autoAcceptConnections: false
});
function originIsAllowed(origin) {
// put logic here to detect whether the specified origin is allowed.
return true;
}
wsServer.on('request', function(request) {
if (!originIsAllowed(request.origin)) {
// Make sure we only accept requests from an allowed origin
request.reject();
console.log((new Date()) + ' Connection from origin ' + request.origin + ' rejected.');
return;
}
var connection = request.accept('echo-protocol', request.origin);
console.log((new Date()) + ' Connection accepted.');
connection.on('message', function(message) {
if (message.type === 'utf8') {
console.log('Received Message: ' + message.utf8Data);
connection.sendUTF(message.utf8Data);
}
else if (message.type === 'binary') {
console.log('Received Binary Message of ' + message.binaryData.length + ' bytes');
connection.sendBytes(message.binaryData);
}
});
connection.on('close', function(reasonCode, description) {
console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
});
});
This solved my problem and I am now getting the message back.
A websocket is not a plain TCP socket. That is basically the core of your problem.
The websocket protocol looks like a modified HTTP protocol that allows two way communication using a single (TCP) socket. Read the RFC for more info on how the websocket protocol actually works: https://www.rfc-editor.org/rfc/rfc6455#section-1.2
You have two options if you want to use websockets with node servers:
Read the RFC and write a function to handle the websocket protocol so you can pass that function to socket.on.
Use a websocket server module that someone else have written. Go to npm and search for "websocket server" or google "websocket server npm". There are lots of modules out there. Pick one you like best.
There is a third alternative. Use socket.io. Socket.io is a library that communicates between client and server using websocket if possible (preferred) but is able to degrade to other transports such as Flash and ajax on older browsers.
I have a Socket.io server and a basic HTTP server that I coded together, but the problem is that the HTTP-server tries to serve requests that socket.io should serve.
Code:
//Dependences
var sio = require('socket.io');
var http = require("http");
var NewRequestHandler = require('./NewRequestHandler').Handler;
var DisconnectHandler = require('./DisconnectHandler').Handler;
var AuthorisationRequestHandler = require('./AuthorisationRequestHandler').Handler;
//The backlog of resources
var ResourceBackLog;
var ResourceRequestHandler = require("./ResourceRequestHandler").Handler;
//Reports the IP adress and Port that it will run on.
console.log('IP address: ' + process.env.IP);
console.log('Port: ' + process.env.PORT);
//Creates and configures a new http.server instance.
var Server = new http.Server();
//Starts both the http and socket.io server.
var io = sio.listen(Server.listen(process.env.PORT, process.env.IP, ResourceBackLog, function(error) {
if (error) {
console.log("Error: " + error);
} else if (!error) {
console.log("Server started sucsessfully.");
Server.on('request', ResourceRequestHandler);
console.log("Server now ready for requests.");
}
}));
//Handles the connect and authorisation bit
io.sockets.on('connection', function(socket) {
console.log('New Connection');
socket.on('auth', function(Keys) {
console.log('Autorisation Request Recived');
AuthorisationRequestHandler(socket, Keys, function() {
socket.on('NewRequest', function(Request) {
NewRequestHandler(socket, Request);
});
socket.on('diconnect', function() {
DisconnectHandler(socket);
});
});
});
});
The ResourceRequestHandler is the file that serves resources by checking the URL then opening the file at that location,
but it also serves /socket.io requests.
I would have Socket.io listen on another port and have the regular http server direct requests to it that way you can be sure they won't interfere with each other.
// create server
io = http.createServer();
io.on('uncaughtException', function(exception) {
console.log(exception);
});
io.listen(4001);
http.createServer(RequestHandler) and new http.Server(RequestHandler) work
Based on Socket.IO 0.9.6.
It is important to attach your custom request listener before the socket.io one. Socket.IO will then serve the requests it can and delegate all the others to your own request listener.
The algorithm in socket.io/lib/manger.js, is as follows.
In constructor:
1. remove all the existing request listeners.
2. attach Socket.IO request listener.
On request:
1. try to handle the request.
2. if Socket.IO cannot handle it, it delegates the request to the original listeners - those which were earlier removed in the constructor.